From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga03.intel.com (mga03.intel.com [134.134.136.65]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 7F7E8817B2 for ; Sun, 8 Jan 2017 18:05:52 -0800 (PST) Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by orsmga103.jf.intel.com with ESMTP; 08 Jan 2017 18:05:51 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.33,338,1477983600"; d="scan'208";a="50943559" Received: from fmsmsx107.amr.corp.intel.com ([10.18.124.205]) by fmsmga005.fm.intel.com with ESMTP; 08 Jan 2017 18:05:51 -0800 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by fmsmsx107.amr.corp.intel.com (10.18.124.205) with Microsoft SMTP Server (TLS) id 14.3.248.2; Sun, 8 Jan 2017 18:05:48 -0800 Received: from shsmsx101.ccr.corp.intel.com ([169.254.1.177]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.204]) with mapi id 14.03.0248.002; Mon, 9 Jan 2017 10:05:44 +0800 From: "Wei, David" To: "Lu, ShifeiX A" , "edk2-devel@lists.01.org" CC: "Wei, David" Thread-Topic: [Patch][edk2-platforms/devel-MinnowBoard3] Fix build error. Thread-Index: AQHSahlQHNN1Z5E33kG9Hba/JIfHHqEvZVcg Date: Mon, 9 Jan 2017 02:05:42 +0000 Message-ID: <89954A0B46707A448411A627AD4EEE3468EEFF47@SHSMSX101.ccr.corp.intel.com> References: In-Reply-To: Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [Patch][edk2-platforms/devel-MinnowBoard3] Fix build error. X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Jan 2017 02:05:52 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: zwei4 Thanks, David Wei =20 -----Original Message----- From: Lu, ShifeiX A=20 Sent: Monday, January 09, 2017 9:39 AM To: edk2-devel@lists.01.org Cc: Wei, David Subject: [Patch][edk2-platforms/devel-MinnowBoard3] Fix build error. Fix build error for latest VS2015 compiler with IA32 tip. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: lushifex --- .../NetworkPkg/UefiPxeBcDxe/ComponentName.c | 358 +++ .../SampleCode/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c | 1259 ++++++++++ .../SampleCode/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.h | 100 + .../NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c | 1672 ++++++++++++++ .../NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.h | 409 ++++ .../NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 2096 ++++++++++++++++= + .../NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 303 +++ .../NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c | 1825 +++++++++++++++ .../NetworkPkg/UefiPxeBcDxe/PxeBcDriver.h | 181 ++ .../SampleCode/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c | 2411 ++++++++++++++++= ++++ .../SampleCode/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h | 225 ++ .../NetworkPkg/UefiPxeBcDxe/PxeBcMtftp.c | 1113 +++++++++ .../NetworkPkg/UefiPxeBcDxe/PxeBcMtftp.h | 137 ++ .../NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c | 1513 ++++++++++++ .../NetworkPkg/UefiPxeBcDxe/PxeBcSupport.h | 515 +++++ .../NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf | 109 + .../NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.uni | Bin 0 -> 2416 bytes .../NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxeExtra.uni | Bin 0 -> 1332 bytes .../BroxtonPlatformPkg/PlatformDsc/Components.dsc | 4 +- Platform/BroxtonPlatformPkg/PlatformPkg.fdf | 4 +- .../Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c | 5 +- 21 files changed, 14233 insertions(+), 6 deletions(-) create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/ComponentName.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcBoot.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcBoot.h create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcDhcp4.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcDhcp4.h create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcDhcp6.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcDhcp6.h create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcDriver.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcDriver.h create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcImpl.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcImpl.h create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcMtftp.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcMtftp.h create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcSupport.c create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/PxeBcSupport.h create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/UefiPxeBcDxe.inf create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/UefiPxeBcDxe.uni create mode 100644 Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPk= g/UefiPxeBcDxe/UefiPxeBcDxeExtra.uni diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/ComponentName.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Net= workPkg/UefiPxeBcDxe/ComponentName.c new file mode 100644 index 0000000..1a81e22 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /ComponentName.c @@ -0,0 +1,358 @@ +/** @file + UEFI Component Name(2) protocol implementation for UefiPxeBc driver. + + Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + +/** + Retrieves a Unicode string that is the user-readable name of the driver. + + This function retrieves the user-readable name of a driver in the form o= f a + Unicode string. If the driver specified by This has a user-readable name= in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver speci= fied + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is the + language of the driver name that the calle= r 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. Language is specifie= d + in RFC 4646 or ISO 639-2 language code for= mat. + + @param[out] 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. + + @retval EFI_SUCCESS The Unicode string for the Driver specifie= d by + This and the language specified by Languag= e was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +PxeBcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ); + + +/** + Retrieves a Unicode string that is the user-readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user-readable name of the controller specifi= ed by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user-readable name in the language specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does = not + support the language specified by Language, then EFI_UNSUPPORTED is retu= rned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handl= e + specifies the controller whose name is to = be + returned. + + @param[in] ChildHandle The handle of the child controller to retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + 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. + + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is th= e + language of the driver name that the calle= r 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. Language is specifie= d in + RFC 4646 or ISO 639-2 language code format= . + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable n= ame in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL, and it is not a v= alid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +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 +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPxeBcCompone= ntName =3D { + PxeBcComponentNameGetDriverName, + PxeBcComponentNameGetControllerName, + "eng" +}; + +// +// EFI Component Name 2 Protocol +// +GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPxeBcCompone= ntName2 =3D { + (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PxeBcComponentNameGetDriverName, + (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PxeBcComponentNameGetControlle= rName, + "en" +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPxeBcDriverN= ameTable[] =3D { + { + "eng;en", + L"UEFI PXE Base Code Driver" + }, + { + NULL, + NULL + } +}; + +GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPxeBcControl= lerNameTable[] =3D { + { + "eng;en", + L"PXE Controller" + }, + { + NULL, + NULL + } +}; + +/** + Retrieves a Unicode string that is the user-readable name of the driver. + + This function retrieves the user-readable name of a driver in the form o= f a + Unicode string. If the driver specified by This has a user-readable name= in + the language specified by Language, then a pointer to the driver name is + returned in DriverName, and EFI_SUCCESS is returned. If the driver speci= fied + by This does not support the language specified by Language, + then EFI_UNSUPPORTED is returned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is the + language of the driver name that the calle= r 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. Language is specifie= d + in RFC 4646 or ISO 639-2 language code for= mat. + + @param[out] 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. + + @retval EFI_SUCCESS The Unicode string for the Driver specifie= d by + This and the language specified by Languag= e was + returned in DriverName. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER DriverName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +EFI_STATUS +EFIAPI +PxeBcComponentNameGetDriverName ( + IN EFI_COMPONENT_NAME_PROTOCOL *This, + IN CHAR8 *Language, + OUT CHAR16 **DriverName + ) +{ + return LookupUnicodeString2( + Language, + This->SupportedLanguages, + mPxeBcDriverNameTable, + DriverName, + (BOOLEAN)(This =3D=3D &gPxeBcComponentName) + ); +} + + +/** + Retrieves a Unicode string that is the user-readable name of the control= ler + that is being managed by a driver. + + This function retrieves the user-readable name of the controller specifi= ed by + ControllerHandle and ChildHandle in the form of a Unicode string. If the + driver specified by This has a user-readable name in the language specif= ied by + Language, then a pointer to the controller name is returned in Controlle= rName, + and EFI_SUCCESS is returned. If the driver specified by This is not cur= rently + managing the controller specified by ControllerHandle and ChildHandle, + then EFI_UNSUPPORTED is returned. If the driver specified by This does = not + support the language specified by Language, then EFI_UNSUPPORTED is retu= rned. + + @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTO= COL or + EFI_COMPONENT_NAME_PROTOCOL instance. + + @param[in] ControllerHandle The handle of a controller that the driver + specified by This is managing. This handl= e + specifies the controller whose name is to = be + returned. + + @param[in] ChildHandle The handle of the child controller to retr= ieve + the name of. This is an optional paramete= r that + may be NULL. It will be NULL for device + drivers. It will also be NULL for a bus d= rivers + 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. + + @param[in] Language A pointer to a Null-terminated ASCII strin= g + array indicating the language. This is th= e + language of the driver name that the calle= r 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. Language is specifie= d in + RFC 4646 or ISO 639-2 language code format= . + + @param[out] ControllerName A pointer to the Unicode string to return. + This Unicode string is the name of the + controller specified by ControllerHandle a= nd + ChildHandle in the language specified by + Language from the point of view of the dri= ver + specified by This. + + @retval EFI_SUCCESS The Unicode string for the user-readable n= ame in + the language specified by Language for the + driver specified by This was returned in + DriverName. + + @retval EFI_INVALID_PARAMETER ControllerHandle is NULL. + + @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a va= lid + EFI_HANDLE. + + @retval EFI_INVALID_PARAMETER Language is NULL. + + @retval EFI_INVALID_PARAMETER ControllerName is NULL. + + @retval EFI_UNSUPPORTED The driver specified by This is not curren= tly + managing the controller specified by + ControllerHandle and ChildHandle. + + @retval EFI_UNSUPPORTED The driver specified by This does not supp= ort + the language specified by Language. + +**/ +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_STATUS Status; + EFI_HANDLE NicHandle; + PXEBC_PRIVATE_PROTOCOL *Id; + + if (ControllerHandle =3D=3D NULL || ChildHandle !=3D NULL) { + return EFI_UNSUPPORTED; + } + =20 + NicHandle =3D PxeBcGetNicByIp4Children (ControllerHandle); + if (NicHandle =3D=3D NULL) { + NicHandle =3D PxeBcGetNicByIp6Children (ControllerHandle); + if (NicHandle =3D=3D NULL) { + return EFI_UNSUPPORTED; + } + } + + // + // Try to retrieve the private data by PxeBcPrivate protocol. + // + Status =3D gBS->OpenProtocol ( + NicHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return LookupUnicodeString2 ( + Language, + This->SupportedLanguages, + mPxeBcControllerNameTable, + ControllerName, + (BOOLEAN)(This =3D=3D &gPxeBcComponentName) + ); +} diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcBoot.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Network= Pkg/UefiPxeBcDxe/PxeBcBoot.c new file mode 100644 index 0000000..504fac6 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcBoot.c @@ -0,0 +1,1259 @@ +/** @file + Boot functions implementation for UefiPxeBc Driver. + + Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + + +/** + Display the string of the boot item. + + If the length of the boot item string beyond 70 Char, just display 70 Ch= ar. + + @param[in] Str The pointer to the string. + @param[in] Len The length of the string. + +**/ +VOID +PxeBcDisplayBootItem ( + IN UINT8 *Str, + IN UINT8 Len + ) +{ + UINT8 Tmp; + + // + // Cut off the chars behind 70th. + // + Len =3D (UINT8) MIN (PXEBC_DISPLAY_MAX_LINE, Len); + Tmp =3D Str[Len]; + Str[Len] =3D 0; + AsciiPrint ("%a \n", Str); + + // + // Restore the original 70th char. + // + Str[Len] =3D Tmp; +} + + +/** + Select and maintain the boot prompt if needed. + + @param[in] Private Pointer to PxeBc private data. + + @retval EFI_SUCCESS Selected boot prompt done. + @retval EFI_TIMEOUT Selected boot prompt timed out. + @retval EFI_NOT_FOUND The proxy offer is not Pxe10. + @retval EFI_ABORTED User cancelled the operation. + @retval EFI_NOT_READY Reading the input key from the keyboard has= not finish. + +**/ +EFI_STATUS +PxeBcSelectBootPrompt ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + PXEBC_DHCP_PACKET_CACHE *Cache; + PXEBC_VENDOR_OPTION *VendorOpt; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_EVENT TimeoutEvent; + EFI_EVENT DescendEvent; + EFI_INPUT_KEY InputKey; + EFI_STATUS Status; + UINT32 OfferType; + UINT8 Timeout; + UINT8 *Prompt; + UINT8 PromptLen; + INT32 SecCol; + INT32 SecRow; + + TimeoutEvent =3D NULL; + DescendEvent =3D NULL; + Mode =3D Private->PxeBc.Mode; + Cache =3D Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Priv= ate->DhcpAck; + OfferType =3D Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4= .OfferType; + + // + // Only DhcpPxe10 and ProxyPxe10 offer needs boot prompt. + // + if (OfferType !=3D PxeOfferTypeProxyPxe10 && OfferType !=3D PxeOfferType= DhcpPxe10) { + return EFI_NOT_FOUND; + } + + // + // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec. + // + ASSERT (!Mode->UsingIpv6); + + VendorOpt =3D &Cache->Dhcp4.VendorOpt; + // + // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options, + // we must not consider a boot prompt or boot menu if all of the followi= ng hold: + // - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Opt= ions(43), and has bit 3 set =20 + // - a boot file name has been presented in the initial DHCP or ProxyD= HCP offer packet. + // + if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && + Cache->Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] !=3D NULL) { + return EFI_ABORTED; + } + =20 + if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) { + return EFI_TIMEOUT; + } + + Timeout =3D VendorOpt->MenuPrompt->Timeout; + Prompt =3D VendorOpt->MenuPrompt->Prompt; + PromptLen =3D (UINT8) (VendorOpt->MenuPromptLen - 1); + + // + // The valid scope of Timeout refers to PXE2.1 spec. + // + if (Timeout =3D=3D 0) { + return EFI_TIMEOUT; + } + if (Timeout =3D=3D 255) { + return EFI_SUCCESS; + } + + // + // Create and start a timer as timeout event. + // + Status =3D gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TimeoutEvent + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D gBS->SetTimer ( + TimeoutEvent, + TimerRelative, + MultU64x32 (Timeout, TICKS_PER_SECOND) + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Create and start a periodic timer as descend event by second. + // + Status =3D gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &DescendEvent + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status =3D gBS->SetTimer ( + DescendEvent, + TimerPeriodic, + TICKS_PER_SECOND + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Display the boot item and cursor on the screen. + // + SecCol =3D gST->ConOut->Mode->CursorColumn; + SecRow =3D gST->ConOut->Mode->CursorRow; + + PxeBcDisplayBootItem (Prompt, PromptLen); + + gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow)= ; + AsciiPrint ("(%d) ", Timeout--); + + Status =3D EFI_TIMEOUT; + while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) { + gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, Sec= Row); + AsciiPrint ("(%d) ", Timeout--); + } + if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) =3D=3D EFI_NOT_R= EADY) { + gBS->Stall (10 * TICKS_PER_MS); + continue; + } + // + // Parse the input key by user. + // If or + is pressed, return success to display the b= oot menu. + // + if (InputKey.ScanCode =3D=3D 0) { + + switch (InputKey.UnicodeChar) { + + case CTRL ('c'): + Status =3D EFI_ABORTED; + break; + + case CTRL ('m'): + case 'm': + case 'M': + Status =3D EFI_SUCCESS; + break; + + default: + continue; + } + + } else { + + switch (InputKey.ScanCode) { + + case SCAN_F8: + Status =3D EFI_SUCCESS; + break; + + case SCAN_ESC: + Status =3D EFI_ABORTED; + break; + + default: + continue; + } + } + + break; + } + + // + // Reset the cursor on the screen. + // + gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1); + +ON_EXIT: + if (DescendEvent !=3D NULL) { + gBS->CloseEvent (DescendEvent); + } + if (TimeoutEvent !=3D NULL) { + gBS->CloseEvent (TimeoutEvent); + } + + return Status; +} + + +/** + Select the boot menu by user's input. + + @param[in] Private Pointer to PxeBc private data. + @param[out] Type The type of the menu. + @param[in] UseDefaultItem Use default item or not. + + @retval EFI_ABORTED User cancel operation. + @retval EFI_SUCCESS Select the boot menu success. + @retval EFI_NOT_READY Read the input key from the keybroad has not fin= ish. + +**/ +EFI_STATUS +PxeBcSelectBootMenu ( + IN PXEBC_PRIVATE_DATA *Private, + OUT UINT16 *Type, + IN BOOLEAN UseDefaultItem + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + PXEBC_DHCP_PACKET_CACHE *Cache; + PXEBC_VENDOR_OPTION *VendorOpt; + EFI_INPUT_KEY InputKey; + UINT32 OfferType; + UINT8 MenuSize; + UINT8 MenuNum; + INT32 TopRow; + UINT16 Select; + UINT16 LastSelect; + UINT8 Index; + BOOLEAN Finish; + CHAR8 Blank[PXEBC_DISPLAY_MAX_LINE]; + PXEBC_BOOT_MENU_ENTRY *MenuItem; + PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MENU_MAX_NUM]; + + Finish =3D FALSE; + Select =3D 0; + Index =3D 0; + *Type =3D 0; + Mode =3D Private->PxeBc.Mode; + Cache =3D Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Private= ->DhcpAck; + OfferType =3D Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.Of= ferType; + + // + // There is no specified DhcpPxe10/ProxyPxe10 for IPv6 in PXE and UEFI s= pec. + // + ASSERT (!Mode->UsingIpv6); + ASSERT (OfferType =3D=3D PxeOfferTypeProxyPxe10 || OfferType =3D=3D PxeO= fferTypeDhcpPxe10); + + VendorOpt =3D &Cache->Dhcp4.VendorOpt; + if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) { + return EFI_SUCCESS; + } + + // + // Display the boot menu on the screen. + // + SetMem (Blank, sizeof(Blank), ' '); + + MenuSize =3D VendorOpt->BootMenuLen; + MenuItem =3D VendorOpt->BootMenu; + + if (MenuSize =3D=3D 0) { + return EFI_DEVICE_ERROR; + } + + while (MenuSize > 0 && Index < PXEBC_MENU_MAX_NUM) { + ASSERT (MenuItem !=3D NULL); + MenuArray[Index] =3D MenuItem; + MenuSize =3D (UINT8) (MenuSize - (MenuItem->DescLen + 3)); + MenuItem =3D (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + = MenuItem->DescLen + 3); + Index++; + } + + if (UseDefaultItem) { + ASSERT (MenuArray[0] !=3D NULL); + CopyMem (Type, &MenuArray[0]->Type, sizeof (UINT16)); + *Type =3D NTOHS (*Type); + return EFI_SUCCESS; + } + + MenuNum =3D Index; + + for (Index =3D 0; Index < MenuNum; Index++) { + ASSERT (MenuArray[Index] !=3D NULL); + PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->Des= cLen); + } + + TopRow =3D gST->ConOut->Mode->CursorRow - MenuNum; + + // + // Select the boot item by user in the boot menu. + // + do { + // + // Highlight selected row. + // + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_= LIGHTGRAY)); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select); + ASSERT (Select < PXEBC_MENU_MAX_NUM); + ASSERT (MenuArray[Select] !=3D NULL); + Blank[MenuArray[Select]->DescLen] =3D 0; + AsciiPrint ("%a\r", Blank); + PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->D= escLen); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum); + LastSelect =3D Select; + + while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) =3D=3D EFI_NO= T_READY) { + gBS->Stall (10 * TICKS_PER_MS); + } + + if (InputKey.ScanCode =3D=3D 0) { + switch (InputKey.UnicodeChar) { + case CTRL ('c'): + InputKey.ScanCode =3D SCAN_ESC; + break; + + case CTRL ('j'): /* linefeed */ + case CTRL ('m'): /* return */ + Finish =3D TRUE; + break; + + case CTRL ('i'): /* tab */ + case ' ': + case 'd': + case 'D': + InputKey.ScanCode =3D SCAN_DOWN; + break; + + case CTRL ('h'): /* backspace */ + case 'u': + case 'U': + InputKey.ScanCode =3D SCAN_UP; + break; + + default: + InputKey.ScanCode =3D 0; + } + } + + switch (InputKey.ScanCode) { + case SCAN_LEFT: + case SCAN_UP: + if (Select !=3D 0) { + Select--; + } + break; + + case SCAN_DOWN: + case SCAN_RIGHT: + if (++Select =3D=3D MenuNum) { + Select--; + } + break; + + case SCAN_PAGE_UP: + case SCAN_HOME: + Select =3D 0; + break; + + case SCAN_PAGE_DOWN: + case SCAN_END: + Select =3D (UINT16) (MenuNum - 1); + break; + + case SCAN_ESC: + return EFI_ABORTED; + } + + // + // Unhighlight the last selected row. + // + gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, = EFI_BLACK)); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect); + ASSERT (LastSelect < PXEBC_MENU_MAX_NUM); + ASSERT (MenuArray[LastSelect] !=3D NULL); + Blank[MenuArray[LastSelect]->DescLen] =3D 0; + AsciiPrint ("%a\r", Blank); + PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSe= lect]->DescLen); + gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum); + } while (!Finish); + + // + // Swap the byte order. + // + ASSERT (Select < PXEBC_MENU_MAX_NUM); + ASSERT (MenuArray[Select] !=3D NULL); + CopyMem (Type, &MenuArray[Select]->Type, sizeof (UINT16)); + *Type =3D NTOHS (*Type); + + return EFI_SUCCESS; +} + + +/** + Parse out the boot information from the last Dhcp4 reply packet. + + @param[in, out] Private Pointer to PxeBc private data. + @param[out] BufferSize Size of the boot file to be downloaded. + + @retval EFI_SUCCESS Successfully parsed out all the boot inform= ation. + @retval Others Failed to parse out the boot information. + +**/ +EFI_STATUS +PxeBcDhcp4BootInfo ( + IN OUT PXEBC_PRIVATE_DATA *Private, + OUT UINT64 *BufferSize + ) +{ + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_STATUS Status; + PXEBC_DHCP4_PACKET_CACHE *Cache4; + UINT16 Value; + PXEBC_VENDOR_OPTION *VendorOpt; + PXEBC_BOOT_SVR_ENTRY *Entry; + =20 + PxeBc =3D &Private->PxeBc; + Mode =3D PxeBc->Mode; + Status =3D EFI_SUCCESS; + *BufferSize =3D 0; + + // + // Get the last received Dhcp4 reply packet. + // + if (Mode->PxeReplyReceived) { + Cache4 =3D &Private->PxeReply.Dhcp4; + } else if (Mode->ProxyOfferReceived) { + Cache4 =3D &Private->ProxyOffer.Dhcp4; + } else { + Cache4 =3D &Private->DhcpAck.Dhcp4; + } + + ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] !=3D NULL); + + // + // Parse the boot server address. + // If prompt/discover is disabled, get the first boot server from the bo= ot servers list. + // Otherwise, parse the boot server Ipv4 address from next server addres= s field in DHCP header. + // If all these fields are not available, use option 54 instead. + // + VendorOpt =3D &Cache4->VendorOpt; + if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && IS_VALID_BOOT_SE= RVERS (VendorOpt->BitMap)) { + Entry =3D VendorOpt->BootSvr; + if (VendorOpt->BootSvrLen >=3D sizeof (PXEBC_BOOT_SVR_ENTRY) && Entry-= >IpCnt > 0) { + CopyMem ( + &Private->ServerIp, + &Entry->IpAddr[0], + sizeof (EFI_IPv4_ADDRESS) + ); + } + } + if (Private->ServerIp.Addr[0] =3D=3D 0) { + // + // ServerIp.Addr[0] equals zero means we failed to get IP address from= boot server list. + // Try to use next server address field. + // + CopyMem ( + &Private->ServerIp, + &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr, + sizeof (EFI_IPv4_ADDRESS) + ); + } + if (Private->ServerIp.Addr[0] =3D=3D 0) { + // + // Still failed , use the IP address from option 54. + // + CopyMem ( + &Private->ServerIp, + Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data, + sizeof (EFI_IPv4_ADDRESS) + ); + } + + // + // Parse the boot file name by option. + // + Private->BootFileName =3D Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE= ]->Data; + + if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] !=3D NULL) { + // + // Parse the boot file size by option. + // + CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->= Data, sizeof (Value)); + Value =3D NTOHS (Value); + // + // The field of boot file size is 512 bytes in unit. + // + *BufferSize =3D 512 * Value; + } else { + // + // Get the bootfile size by tftp command if no option available. + // + Status =3D PxeBc->Mtftp ( + PxeBc, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + NULL, + FALSE, + BufferSize, + &Private->BlockSize, + &Private->ServerIp, + Private->BootFileName, + NULL, + FALSE + ); + } + + // + // Save the value of boot file size. + // + Private->BootFileSize =3D (UINTN) *BufferSize; + + // + // Display all the information: boot server address, boot file name and = boot file size. + // + AsciiPrint ("\n Server IP address is "); + PxeBcShowIp4Addr (&Private->ServerIp.v4); + AsciiPrint ("\n NBP filename is %a", Private->BootFileName); + AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize); + + return Status; +} + + +/** + Parse out the boot information from the last Dhcp6 reply packet. + + @param[in, out] Private Pointer to PxeBc private data. + @param[out] BufferSize Size of the boot file to be downloaded. + + @retval EFI_SUCCESS Successfully parsed out all the boot inform= ation. + @retval EFI_BUFFER_TOO_SMALL + @retval Others Failed to parse out the boot information. + +**/ +EFI_STATUS +PxeBcDhcp6BootInfo ( + IN OUT PXEBC_PRIVATE_DATA *Private, + OUT UINT64 *BufferSize + ) +{ + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_STATUS Status; + PXEBC_DHCP6_PACKET_CACHE *Cache6; + UINT16 Value; + + PxeBc =3D &Private->PxeBc; + Mode =3D PxeBc->Mode; + Status =3D EFI_SUCCESS; + *BufferSize =3D 0; + + // + // Get the last received Dhcp6 reply packet. + // + if (Mode->PxeReplyReceived) { + Cache6 =3D &Private->PxeReply.Dhcp6; + } else if (Mode->ProxyOfferReceived) { + Cache6 =3D &Private->ProxyOffer.Dhcp6; + } else { + Cache6 =3D &Private->DhcpAck.Dhcp6; + } + + ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] !=3D NULL); + + // + // Parse (m)tftp server ip address and bootfile name. + // + Status =3D PxeBcExtractBootFileUrl ( + &Private->BootFileName, + &Private->ServerIp.v6, + (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Da= ta), + NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen) + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set the station address to IP layer. + // + Status =3D PxeBcSetIp6Address (Private); + if (EFI_ERROR (Status)) { + return Status; + } + =20 + // + // Parse the value of boot file size. + // + if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] !=3D NULL) { + // + // Parse it out if have the boot file parameter option. + // + Status =3D PxeBcExtractBootFileParam ((CHAR8 *) Cache6->OptList[PXEBC_= DHCP6_IDX_BOOT_FILE_PARAM]->Data, &Value); + if (EFI_ERROR (Status)) { + return Status; + } + // + // The field of boot file size is 512 bytes in unit. + // + *BufferSize =3D 512 * Value; + } else { + // + // Send get file size command by tftp if option unavailable. + // + Status =3D PxeBc->Mtftp ( + PxeBc, + EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, + NULL, + FALSE, + BufferSize, + &Private->BlockSize, + &Private->ServerIp, + Private->BootFileName, + NULL, + FALSE + ); + } + + // + // Save the value of boot file size. + // + Private->BootFileSize =3D (UINTN) *BufferSize; + + // + // Display all the information: boot server address, boot file name and = boot file size. + // + AsciiPrint ("\n Server IP address is "); + PxeBcShowIp6Addr (&Private->ServerIp.v6); + AsciiPrint ("\n NBP filename is %a", Private->BootFileName); + AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize); + + return Status; +} + + +/** + Extract the discover information and boot server entry from the + cached packets if unspecified. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Type The type of bootstrap to perform. + @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO. + @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY. + @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST. + + @retval EFI_SUCCESS Successfully extracted the information. + @retval EFI_DEVICE_ERROR Failed to extract the information. + +**/ +EFI_STATUS +PxeBcExtractDiscoverInfo ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO **DiscoverInfo, + OUT PXEBC_BOOT_SVR_ENTRY **BootEntry, + OUT EFI_PXE_BASE_CODE_SRVLIST **SrvList + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + PXEBC_DHCP4_PACKET_CACHE *Cache4; + PXEBC_VENDOR_OPTION *VendorOpt; + PXEBC_BOOT_SVR_ENTRY *Entry; + BOOLEAN IsFound; + EFI_PXE_BASE_CODE_DISCOVER_INFO *Info; + UINT16 Index; + + Mode =3D Private->PxeBc.Mode; + Info =3D *DiscoverInfo; + + if (Mode->UsingIpv6) { + Info->IpCnt =3D 1; + Info->UseUCast =3D TRUE; + + Info->SrvList[0].Type =3D Type; + Info->SrvList[0].AcceptAnyResponse =3D FALSE; + + // + // There is no vendor options specified in DHCPv6, so take BootFileUrl= in the last cached packet. + // + CopyMem (&Info->SrvList[0].IpAddr, &Private->ServerIp, sizeof (EFI_IP_= ADDRESS)); + + *SrvList =3D Info->SrvList; + } else { + Entry =3D NULL; + IsFound =3D FALSE; + Cache4 =3D (Mode->ProxyOfferReceived) ? &Private->ProxyOffer.Dhcp4 = : &Private->DhcpAck.Dhcp4; + VendorOpt =3D &Cache4->VendorOpt; + + if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (Vendor= Opt->BitMap)) { + // + // Address is not acquired or no discovery options. + // + return EFI_INVALID_PARAMETER; + } + + // + // Parse the boot server entry from the vendor option in the last cach= ed packet. + // + Info->UseMCast =3D (BOOLEAN) !IS_DISABLE_MCAST_DISCOVER (VendorOpt-= >DiscoverCtrl); + Info->UseBCast =3D (BOOLEAN) !IS_DISABLE_BCAST_DISCOVER (VendorOpt-= >DiscoverCtrl); + Info->MustUseList =3D (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->= DiscoverCtrl); + Info->UseUCast =3D (BOOLEAN) IS_VALID_BOOT_SERVERS (VendorOpt->BitM= ap); + + if (Info->UseMCast) { + // + // Get the multicast discover ip address from vendor option if has. + // + CopyMem (&Info->ServerMCastIp.v4, &VendorOpt->DiscoverMcastIp, sizeo= f (EFI_IPv4_ADDRESS)); + } + + Info->IpCnt =3D 0; + + if (Info->UseUCast) { + Entry =3D VendorOpt->BootSvr; + + while (((UINT8) (Entry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLe= n) { + if (Entry->Type =3D=3D HTONS (Type)) { + IsFound =3D TRUE; + break; + } + Entry =3D GET_NEXT_BOOT_SVR_ENTRY (Entry); + } + + if (!IsFound) { + return EFI_DEVICE_ERROR; + } + + Info->IpCnt =3D Entry->IpCnt; + if (Info->IpCnt >=3D 1) { + *DiscoverInfo =3D AllocatePool (sizeof (*Info) + (Info->IpCnt - 1)= * sizeof (**SrvList)); + if (*DiscoverInfo =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; =20 + } =20 + CopyMem (*DiscoverInfo, Info, sizeof (*Info)); + Info =3D *DiscoverInfo; + } + + for (Index =3D 0; Index < Info->IpCnt; Index++) { + CopyMem (&Info->SrvList[Index].IpAddr, &Entry->IpAddr[Index], size= of (EFI_IPv4_ADDRESS)); + Info->SrvList[Index].AcceptAnyResponse =3D !Info->MustUseList; + Info->SrvList[Index].Type =3D NTOHS (Entry->Type); + } + } + + *BootEntry =3D Entry; + *SrvList =3D Info->SrvList; + } + + return EFI_SUCCESS; +} + + +/** + Build the discover packet and send out for boot server. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Type PxeBc option boot item type. + @param[in] Layer Pointer to option boot item layer. + @param[in] UseBis Use BIS or not. + @param[in] DestIp Pointer to the destination address. + @param[in] IpCount The count of the server address. + @param[in] SrvList Pointer to the server address list. + + @retval EFI_SUCCESS Successfully discovered boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover boot file. + +**/ +EFI_STATUS +PxeBcDiscoverBootServer ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_IP_ADDRESS *DestIp, + IN UINT16 IpCount, + IN EFI_PXE_BASE_CODE_SRVLIST *SrvList + ) +{ + if (Private->PxeBc.Mode->UsingIpv6) { + return PxeBcDhcp6Discover ( + Private, + Type, + Layer, + UseBis, + DestIp + ); + } else { + return PxeBcDhcp4Discover ( + Private, + Type, + Layer, + UseBis, + DestIp, + IpCount, + SrvList + ); + } +} + + +/** + Discover all the boot information for boot file. + + @param[in, out] Private Pointer to PxeBc private data. + @param[out] BufferSize Size of the boot file to be downloaded. + + @retval EFI_SUCCESS Successfully obtained all the boot informat= ion . + @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file= . + @retval EFI_ABORTED User cancel current operation. + @retval Others Failed to parse out the boot information. + +**/ +EFI_STATUS +PxeBcDiscoverBootFile ( + IN OUT PXEBC_PRIVATE_DATA *Private, + OUT UINT64 *BufferSize + ) +{ + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_STATUS Status; + UINT16 Type; + UINT16 Layer; + BOOLEAN UseBis; + + PxeBc =3D &Private->PxeBc; + Mode =3D PxeBc->Mode; + Type =3D EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP; + Layer =3D EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL; + + // + // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and + // other pxe boot information. + // + Status =3D PxeBc->Dhcp (PxeBc, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Select a boot server from boot server list. + // + Status =3D PxeBcSelectBootPrompt (Private); + + if (Status =3D=3D EFI_SUCCESS) { + // + // Choose by user's input. + // + Status =3D PxeBcSelectBootMenu (Private, &Type, FALSE); + } else if (Status =3D=3D EFI_TIMEOUT) { + // + // Choose by default item. + // + Status =3D PxeBcSelectBootMenu (Private, &Type, TRUE); + } + + if (!EFI_ERROR (Status)) { + + if (Type =3D=3D EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) { + // + // Local boot(PXE bootstrap server) need abort + // + return EFI_ABORTED; + } + + // + // Start to discover the boot server to get (m)tftp server ip address,= bootfile + // name and bootfile size. + // + UseBis =3D (BOOLEAN) (Mode->BisSupported && Mode->BisDetected); + Status =3D PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Mode->PxeReplyReceived && !Mode->ProxyOfferReceived) { + // + // Some network boot loader only search the packet in Mode.ProxyOffe= r to get its server + // IP address, so we need to store a copy of Mode.PxeReply packet in= to Mode.ProxyOffer. + // + if (Mode->UsingIpv6) { + CopyMem ( + &Mode->ProxyOffer.Dhcpv6, + &Mode->PxeReply.Dhcpv6, + Private->PxeReply.Dhcp6.Packet.Ack.Length + ); + } else { + CopyMem ( + &Mode->ProxyOffer.Dhcpv4, + &Mode->PxeReply.Dhcpv4, + Private->PxeReply.Dhcp4.Packet.Ack.Length + ); =20 + } + Mode->ProxyOfferReceived =3D TRUE; + } + } + + // + // Parse the boot information. + // + if (Mode->UsingIpv6) { + Status =3D PxeBcDhcp6BootInfo (Private, BufferSize); + } else { + Status =3D PxeBcDhcp4BootInfo (Private, BufferSize); + } + + return Status; +} + + +/** + Install PxeBaseCodeCallbackProtocol if not installed before. + + @param[in, out] Private Pointer to PxeBc private data. + @param[out] NewMakeCallback If TRUE, it is a new callback. + Otherwise, it is not new callback. + @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed succe= sfully. + @retval Others Failed to install PxeBaseCodeCallbackProtoc= ol. + +**/ +EFI_STATUS +PxeBcInstallCallback ( + IN OUT PXEBC_PRIVATE_DATA *Private, + OUT BOOLEAN *NewMakeCallback + ) +{ + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_STATUS Status; + + // + // Check whether PxeBaseCodeCallbackProtocol already installed. + // + PxeBc =3D &Private->PxeBc; + Status =3D gBS->HandleProtocol ( + Private->Controller, + &gEfiPxeBaseCodeCallbackProtocolGuid, + (VOID **) &Private->PxeBcCallback + ); + if (Status =3D=3D EFI_UNSUPPORTED) { + + CopyMem ( + &Private->LoadFileCallback, + &gPxeBcCallBackTemplate, + sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL) + ); + + // + // Install a default callback if user didn't offer one. + // + Status =3D gBS->InstallProtocolInterface ( + &Private->Controller, + &gEfiPxeBaseCodeCallbackProtocolGuid, + EFI_NATIVE_INTERFACE, + &Private->LoadFileCallback + ); + + (*NewMakeCallback) =3D (BOOLEAN) (Status =3D=3D EFI_SUCCESS); + + Status =3D PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, NewMak= eCallback); + if (EFI_ERROR (Status)) { + PxeBc->Stop (PxeBc); + return Status; + } + } + + return EFI_SUCCESS; +} + + +/** + Uninstall PxeBaseCodeCallbackProtocol. + + @param[in] Private Pointer to PxeBc private data. + @param[in] NewMakeCallback If TRUE, it is a new callback. + Otherwise, it is not new callback. + +**/ +VOID +PxeBcUninstallCallback ( + IN PXEBC_PRIVATE_DATA *Private, + IN BOOLEAN NewMakeCallback + ) +{ + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + + PxeBc =3D &Private->PxeBc; + + if (NewMakeCallback) { + + NewMakeCallback =3D FALSE; + + PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback)= ; + + gBS->UninstallProtocolInterface ( + Private->Controller, + &gEfiPxeBaseCodeCallbackProtocolGuid, + &Private->LoadFileCallback + ); + } +} + + +/** + Download one of boot file in the list, and it's special for IPv6. + + @param[in] Private Pointer to PxeBc private data. + @param[in, out] BufferSize Size of user buffer for input; + required buffer size for output. + @param[in] Buffer Pointer to user buffer. + + @retval EFI_SUCCESS Read one of boot file in the list succ= essfully. + @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot= file. + @retval EFI_NOT_FOUND There is no proper boot file available= . + @retval Others Failed to download boot file in the li= st. + +**/ +EFI_STATUS +PxeBcReadBootFileList ( + IN PXEBC_PRIVATE_DATA *Private, + IN OUT UINT64 *BufferSize, + IN VOID *Buffer OPTIONAL + ) +{ + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + + PxeBc =3D &Private->PxeBc; + + // + // Try to download the boot file if everything is ready. + // + if (Buffer !=3D NULL) { + Status =3D PxeBc->Mtftp ( + PxeBc, + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + Buffer, + FALSE, + BufferSize, + &Private->BlockSize, + &Private->ServerIp, + Private->BootFileName, + NULL, + FALSE + ); + + + } else { + Status =3D EFI_BUFFER_TOO_SMALL; + } + + return Status; +} + + +/** + Load boot file into user buffer. + + @param[in] Private Pointer to PxeBc private data. + @param[in, out] BufferSize Size of user buffer for input; + required buffer size for output. + @param[in] Buffer Pointer to user buffer. + + @retval EFI_SUCCESS Get all the boot information successfully. + @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file= . + @retval EFI_ABORTED User cancelled the current operation. + @retval Others Failed to parse out the boot information. + +**/ +EFI_STATUS +PxeBcLoadBootFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL + ) +{ + BOOLEAN NewMakeCallback; + UINT64 RequiredSize; + UINT64 CurrentSize; + EFI_STATUS Status; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_MODE *PxeBcMode; + + NewMakeCallback =3D FALSE; + PxeBc =3D &Private->PxeBc; + PxeBcMode =3D &Private->Mode; + CurrentSize =3D *BufferSize; + RequiredSize =3D 0; + + // + // Install pxebc callback protocol if hasn't been installed yet. + // + Status =3D PxeBcInstallCallback (Private, &NewMakeCallback); + if (EFI_ERROR(Status)) { + return Status; + } + + if (Private->BootFileSize =3D=3D 0) { + // + // Discover the boot information about the bootfile if hasn't. + // + Status =3D PxeBcDiscoverBootFile (Private, &RequiredSize); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize)) { + // + // It's error if the required buffer size is beyond the system scope= . + // + Status =3D EFI_DEVICE_ERROR; + goto ON_EXIT; + } else if (RequiredSize > 0) { + // + // Get the right buffer size of the bootfile required. + // + if (CurrentSize < RequiredSize || Buffer =3D=3D NULL) { + // + // It's buffer too small if the size of user buffer is smaller tha= n the required. + // + CurrentSize =3D RequiredSize; + Status =3D EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + CurrentSize =3D RequiredSize; + } else if (RequiredSize =3D=3D 0 && PxeBcMode->UsingIpv6) { + // + // Try to download another bootfile in list if failed to get the fil= esize of the last one. + // It's special for the case of IPv6. + // + Status =3D PxeBcReadBootFileList (Private, &CurrentSize, Buffer); + goto ON_EXIT; + } + } else if (CurrentSize < Private->BootFileSize || Buffer =3D=3D NULL ) { + // + // It's buffer too small if the size of user buffer is smaller than th= e required. + // + CurrentSize =3D Private->BootFileSize; + Status =3D EFI_BUFFER_TOO_SMALL; + goto ON_EXIT; + } + + // + // Begin to download the bootfile if everything is ready. + // + AsciiPrint ("\n Downloading NBP file...\n"); + if (PxeBcMode->UsingIpv6) { + Status =3D PxeBcReadBootFileList ( + Private, + &CurrentSize, + Buffer + ); + } else { + Status =3D PxeBc->Mtftp ( + PxeBc, + EFI_PXE_BASE_CODE_TFTP_READ_FILE, + Buffer, + FALSE, + &CurrentSize, + &Private->BlockSize, + &Private->ServerIp, + Private->BootFileName, + NULL, + FALSE + ); + } + +ON_EXIT: + *BufferSize =3D (UINTN) CurrentSize; + PxeBcUninstallCallback(Private, NewMakeCallback); + + if (Status =3D=3D EFI_SUCCESS) { + AsciiPrint ("\n Succeed to download NBP file.\n"); + return EFI_SUCCESS; + } else if (Status =3D=3D EFI_BUFFER_TOO_SMALL && Buffer !=3D NULL) { + AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested fi= le.\n"); + } else if (Status =3D=3D EFI_DEVICE_ERROR) { + AsciiPrint ("\n PXE-E07: Network device error.\n"); + } else if (Status =3D=3D EFI_OUT_OF_RESOURCES) { + AsciiPrint ("\n PXE-E09: Could not allocate I/O buffers.\n"); + } else if (Status =3D=3D EFI_NO_MEDIA) { + AsciiPrint ("\n PXE-E12: Could not detect network connection.\n"); + } else if (Status =3D=3D EFI_NO_RESPONSE) { + AsciiPrint ("\n PXE-E16: No offer received.\n"); + } else if (Status =3D=3D EFI_TIMEOUT) { + AsciiPrint ("\n PXE-E18: Server response timeout.\n"); + } else if (Status =3D=3D EFI_ABORTED) { + AsciiPrint ("\n PXE-E21: Remote boot cancelled.\n"); + } else if (Status =3D=3D EFI_ICMP_ERROR) { + AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n"); + } else if (Status =3D=3D EFI_TFTP_ERROR) { + AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n"); + } else if (Status =3D=3D EFI_NOT_FOUND) { + AsciiPrint ("\n PXE-E53: No boot filename received.\n"); + } else if (Status !=3D EFI_BUFFER_TOO_SMALL) { + AsciiPrint ("\n PXE-E99: Unexpected network error.\n"); + } + + return Status; +} + diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcBoot.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/Network= Pkg/UefiPxeBcDxe/PxeBcBoot.h new file mode 100644 index 0000000..7cfa699 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcBoot.h @@ -0,0 +1,100 @@ +/** @file + Boot functions declaration for UefiPxeBc Driver. + + Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __EFI_PXEBC_BOOT_H__ +#define __EFI_PXEBC_BOOT_H__ + +#define PXEBC_DISPLAY_MAX_LINE 70 +#define PXEBC_DEFAULT_UDP_OVERHEAD_SIZE 8 +#define PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE 4 + +#define PXEBC_IS_SIZE_OVERFLOWED(x) ((sizeof (UINTN) < sizeof (UINT64)) = && ((x) > 0xFFFFFFFF)) + + +/** + Extract the discover information and boot server entry from the + cached packets if unspecified. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Type The type of bootstrap to perform. + @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO. + @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY. + @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST. + + @retval EFI_SUCCESS Successfully extracted the information. + @retval EFI_DEVICE_ERROR Failed to extract the information. + +**/ +EFI_STATUS +PxeBcExtractDiscoverInfo ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO **DiscoverInfo, + OUT PXEBC_BOOT_SVR_ENTRY **BootEntry, + OUT EFI_PXE_BASE_CODE_SRVLIST **SrvList + ); + + +/** + Build the discover packet and send out for boot. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Type PxeBc option boot item type. + @param[in] Layer Pointer to option boot item layer. + @param[in] UseBis Use BIS or not. + @param[in] DestIp Pointer to the server address. + @param[in] IpCount The total count of the server address. + @param[in] SrvList Pointer to the server address list. + + @retval EFI_SUCCESS Successfully discovered boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover boot file. + +**/ +EFI_STATUS +PxeBcDiscoverBootServer ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_IP_ADDRESS *DestIp, + IN UINT16 IpCount, + IN EFI_PXE_BASE_CODE_SRVLIST *SrvList + ); + + +/** + Load boot file into user buffer. + + @param[in] Private Pointer to PxeBc private data. + @param[in, out] BufferSize Size of user buffer for input; + required buffer size for output. + @param[in] Buffer Pointer to user buffer. + + @retval EFI_SUCCESS Successfully obtained all the boot informat= ion. + @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file= . + @retval EFI_ABORTED User cancelled the current operation. + @retval Others Failed to parse out the boot information. + +**/ +EFI_STATUS +PxeBcLoadBootFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL + ); + +#endif diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcDhcp4.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Networ= kPkg/UefiPxeBcDxe/PxeBcDhcp4.c new file mode 100644 index 0000000..3b83121 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcDhcp4.c @@ -0,0 +1,1672 @@ +/** @file + Functions implementation related with DHCPv4 for UefiPxeBc Driver. + + Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + +// +// This is a map from the interested DHCP4 option tags' index to the tag v= alue. +// +UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] =3D { + PXEBC_DHCP4_TAG_BOOTFILE_LEN, + PXEBC_DHCP4_TAG_VENDOR, + PXEBC_DHCP4_TAG_OVERLOAD, + PXEBC_DHCP4_TAG_MSG_TYPE, + PXEBC_DHCP4_TAG_SERVER_ID, + PXEBC_DHCP4_TAG_CLASS_ID, + PXEBC_DHCP4_TAG_BOOTFILE +}; + +// +// There are 4 times retries with the value of 4, 8, 16 and 32, refers to = PXE2.1 spec. +// +UINT32 mPxeDhcpTimeout[4] =3D {4, 8, 16, 32}; + + +/** + Parse a certain dhcp4 option by OptTag in Buffer, and return with start = pointer. + + @param[in] Buffer Pointer to the option buffer. + @param[in] Length Length of the option buffer. + @param[in] OptTag Tag of the required option. + + @retval NULL Failed to find the required option. + @retval Others The position of the required option. + +**/ +EFI_DHCP4_PACKET_OPTION * +PxeBcParseDhcp4Options ( + IN UINT8 *Buffer, + IN UINT32 Length, + IN UINT8 OptTag + ) +{ + EFI_DHCP4_PACKET_OPTION *Option; + UINT32 Offset; + + Option =3D (EFI_DHCP4_PACKET_OPTION *) Buffer; + Offset =3D 0; + + while (Offset < Length && Option->OpCode !=3D PXEBC_DHCP4_TAG_EOP) { + + if (Option->OpCode =3D=3D OptTag) { + // + // Found the required option. + // + return Option; + } + + // + // Skip the current option to the next. + // + if (Option->OpCode =3D=3D PXEBC_DHCP4_TAG_PAD) { + Offset++; + } else { + Offset +=3D Option->Length + 2; + } + + Option =3D (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset); + } + + return NULL; +} + + +/** + Parse the PXE vender options and extract the information from them. + + @param[in] Dhcp4Option Pointer to vendor options in buffer. + @param[in] VendorOption Pointer to structure to store information= in vendor options. + +**/ +VOID +PxeBcParseVendorOptions ( + IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option, + IN PXEBC_VENDOR_OPTION *VendorOption + ) +{ + UINT32 *BitMap; + UINT8 VendorOptionLen; + EFI_DHCP4_PACKET_OPTION *PxeOption; + UINT8 Offset; + + BitMap =3D VendorOption->BitMap; + VendorOptionLen =3D Dhcp4Option->Length; + PxeOption =3D (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0]; + Offset =3D 0; + + ASSERT (PxeOption !=3D NULL); + + while ((Offset < VendorOptionLen) && (PxeOption->OpCode !=3D PXEBC_DHCP4= _TAG_EOP)) { + // + // Parse all the interesting PXE vendor options one by one. + // + switch (PxeOption->OpCode) { + + case PXEBC_VENDOR_TAG_MTFTP_IP: + + CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_A= DDRESS)); + break; + + case PXEBC_VENDOR_TAG_MTFTP_CPORT: + + CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorO= ption->MtftpCPort)); + break; + + case PXEBC_VENDOR_TAG_MTFTP_SPORT: + + CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorO= ption->MtftpSPort)); + break; + + case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT: + + VendorOption->MtftpTimeout =3D *PxeOption->Data; + break; + + case PXEBC_VENDOR_TAG_MTFTP_DELAY: + + VendorOption->MtftpDelay =3D *PxeOption->Data; + break; + + case PXEBC_VENDOR_TAG_DISCOVER_CTRL: + + VendorOption->DiscoverCtrl =3D *PxeOption->Data; + break; + + case PXEBC_VENDOR_TAG_DISCOVER_MCAST: + + CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EF= I_IPv4_ADDRESS)); + break; + + case PXEBC_VENDOR_TAG_BOOT_SERVERS: + + VendorOption->BootSvrLen =3D PxeOption->Length; + VendorOption->BootSvr =3D (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Da= ta; + break; + + case PXEBC_VENDOR_TAG_BOOT_MENU: + + VendorOption->BootMenuLen =3D PxeOption->Length; + VendorOption->BootMenu =3D (PXEBC_BOOT_MENU_ENTRY *) PxeOption->D= ata; + break; + + case PXEBC_VENDOR_TAG_MENU_PROMPT: + + VendorOption->MenuPromptLen =3D PxeOption->Length; + VendorOption->MenuPrompt =3D (PXEBC_MENU_PROMPT *) PxeOption->Dat= a; + break; + + case PXEBC_VENDOR_TAG_MCAST_ALLOC: + + CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IP= v4_ADDRESS)); + CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (V= endorOption->McastIpBlock)); + CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (V= endorOption->McastIpRange)); + break; + + case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES: + + VendorOption->CredTypeLen =3D PxeOption->Length; + VendorOption->CredType =3D (UINT32 *) PxeOption->Data; + break; + + case PXEBC_VENDOR_TAG_BOOT_ITEM: + + CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (Vendor= Option->BootSrvType)); + CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (V= endorOption->BootSrvLayer)); + break; + + default: + // + // Not interesting PXE vendor options. + // + break; + } + + // + // Set the bit map for the special PXE options. + // + SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode); + + // + // Continue to the next option. + // + if (PxeOption->OpCode =3D=3D PXEBC_DHCP4_TAG_PAD) { + Offset++; + } else { + Offset =3D (UINT8) (Offset + PxeOption->Length + 2); + } + + PxeOption =3D (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset)= ; + } +} + + +/** + Build the options buffer for the DHCPv4 request packet. + + @param[in] Private Pointer to PxeBc private data. + @param[out] OptList Pointer to the option pointer array. + @param[in] Buffer Pointer to the buffer to contain the opt= ion list. + @param[in] NeedMsgType If TRUE, it is necessary to include the = Msg type option. + Otherwise, it is not necessary. + + @return Index The count of the built-in options. + +**/ +UINT32 +PxeBcBuildDhcp4Options ( + IN PXEBC_PRIVATE_DATA *Private, + OUT EFI_DHCP4_PACKET_OPTION **OptList, + IN UINT8 *Buffer, + IN BOOLEAN NeedMsgType + ) +{ + UINT32 Index; + PXEBC_DHCP4_OPTION_ENTRY OptEnt; + UINT16 Value; + + Index =3D 0; + OptList[0] =3D (EFI_DHCP4_PACKET_OPTION *) Buffer; + + if (NeedMsgType) { + // + // Append message type. + // + OptList[Index]->OpCode =3D PXEBC_DHCP4_TAG_MSG_TYPE; + OptList[Index]->Length =3D 1; + OptEnt.Mesg =3D (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]= ->Data; + OptEnt.Mesg->Type =3D PXEBC_DHCP4_MSG_TYPE_REQUEST; + Index++; + OptList[Index] =3D GET_NEXT_DHCP_OPTION (OptList[Index - 1]); + + // + // Append max message size. + // + OptList[Index]->OpCode =3D PXEBC_DHCP4_TAG_MAXMSG; + OptList[Index]->Length =3D (UINT8) sizeof (PXEBC_DHCP4_OPTION_MAX_MES= G_SIZE); + OptEnt.MaxMesgSize =3D (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptLi= st[Index]->Data; + Value =3D NTOHS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8); + CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16)); + Index++; + OptList[Index] =3D GET_NEXT_DHCP_OPTION (OptList[Index - 1]); + } + + // + // Append parameter request list option. + // + OptList[Index]->OpCode =3D PXEBC_DHCP4_TAG_PARA_LIST; + OptList[Index]->Length =3D 35; + OptEnt.Para =3D (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]= ->Data; + OptEnt.Para->ParaList[0] =3D PXEBC_DHCP4_TAG_NETMASK; + OptEnt.Para->ParaList[1] =3D PXEBC_DHCP4_TAG_TIME_OFFSET; + OptEnt.Para->ParaList[2] =3D PXEBC_DHCP4_TAG_ROUTER; + OptEnt.Para->ParaList[3] =3D PXEBC_DHCP4_TAG_TIME_SERVER; + OptEnt.Para->ParaList[4] =3D PXEBC_DHCP4_TAG_NAME_SERVER; + OptEnt.Para->ParaList[5] =3D PXEBC_DHCP4_TAG_DNS_SERVER; + OptEnt.Para->ParaList[6] =3D PXEBC_DHCP4_TAG_HOSTNAME; + OptEnt.Para->ParaList[7] =3D PXEBC_DHCP4_TAG_BOOTFILE_LEN; + OptEnt.Para->ParaList[8] =3D PXEBC_DHCP4_TAG_DOMAINNAME; + OptEnt.Para->ParaList[9] =3D PXEBC_DHCP4_TAG_ROOTPATH; + OptEnt.Para->ParaList[10] =3D PXEBC_DHCP4_TAG_EXTEND_PATH; + OptEnt.Para->ParaList[11] =3D PXEBC_DHCP4_TAG_EMTU; + OptEnt.Para->ParaList[12] =3D PXEBC_DHCP4_TAG_TTL; + OptEnt.Para->ParaList[13] =3D PXEBC_DHCP4_TAG_BROADCAST; + OptEnt.Para->ParaList[14] =3D PXEBC_DHCP4_TAG_NIS_DOMAIN; + OptEnt.Para->ParaList[15] =3D PXEBC_DHCP4_TAG_NIS_SERVER; + OptEnt.Para->ParaList[16] =3D PXEBC_DHCP4_TAG_NTP_SERVER; + OptEnt.Para->ParaList[17] =3D PXEBC_DHCP4_TAG_VENDOR; + OptEnt.Para->ParaList[18] =3D PXEBC_DHCP4_TAG_REQUEST_IP; + OptEnt.Para->ParaList[19] =3D PXEBC_DHCP4_TAG_LEASE; + OptEnt.Para->ParaList[20] =3D PXEBC_DHCP4_TAG_SERVER_ID; + OptEnt.Para->ParaList[21] =3D PXEBC_DHCP4_TAG_T1; + OptEnt.Para->ParaList[22] =3D PXEBC_DHCP4_TAG_T2; + OptEnt.Para->ParaList[23] =3D PXEBC_DHCP4_TAG_CLASS_ID; + OptEnt.Para->ParaList[24] =3D PXEBC_DHCP4_TAG_TFTP; + OptEnt.Para->ParaList[25] =3D PXEBC_DHCP4_TAG_BOOTFILE; + OptEnt.Para->ParaList[26] =3D PXEBC_PXE_DHCP4_TAG_UUID; + OptEnt.Para->ParaList[27] =3D 0x80; + OptEnt.Para->ParaList[28] =3D 0x81; + OptEnt.Para->ParaList[29] =3D 0x82; + OptEnt.Para->ParaList[30] =3D 0x83; + OptEnt.Para->ParaList[31] =3D 0x84; + OptEnt.Para->ParaList[32] =3D 0x85; + OptEnt.Para->ParaList[33] =3D 0x86; + OptEnt.Para->ParaList[34] =3D 0x87; + Index++; + OptList[Index] =3D GET_NEXT_DHCP_OPTION (OptList[Index - 1]); + + // + // Append UUID/Guid-based client identifier option + // + OptList[Index]->OpCode =3D PXEBC_PXE_DHCP4_TAG_UUID; + OptList[Index]->Length =3D (UINT8) sizeof (PXEBC_DHCP4_OPTION_UUID); + OptEnt.Uuid =3D (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->= Data; + OptEnt.Uuid->Type =3D 0; + Index++; + OptList[Index] =3D GET_NEXT_DHCP_OPTION (OptList[Index - 1]); + + if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) OptEnt.Uuid->Guid))) { + // + // Zero the Guid to indicate NOT programable if failed to get system G= uid. + // + ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID)); + } + + // + // Append client network device interface option + // + OptList[Index]->OpCode =3D PXEBC_PXE_DHCP4_TAG_UNDI; + OptList[Index]->Length =3D (UINT8) sizeof (PXEBC_DHCP4_OPTION_UNDI); + OptEnt.Undi =3D (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->= Data; + + if (Private->Nii !=3D NULL) { + OptEnt.Undi->Type =3D Private->Nii->Type; + OptEnt.Undi->MajorVer =3D Private->Nii->MajorVer; + OptEnt.Undi->MinorVer =3D Private->Nii->MinorVer; + } else { + OptEnt.Undi->Type =3D DEFAULT_UNDI_TYPE; + OptEnt.Undi->MajorVer =3D DEFAULT_UNDI_MAJOR; + OptEnt.Undi->MinorVer =3D DEFAULT_UNDI_MINOR; + } + + Index++; + OptList[Index] =3D GET_NEXT_DHCP_OPTION (OptList[Index - 1]); + + // + // Append client system architecture option + // + OptList[Index]->OpCode =3D PXEBC_PXE_DHCP4_TAG_ARCH; + OptList[Index]->Length =3D (UINT8) sizeof (PXEBC_DHCP4_OPTION_ARCH); + OptEnt.Arch =3D (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->= Data; + Value =3D HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE); + CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); + Index++; + OptList[Index] =3D GET_NEXT_DHCP_OPTION (OptList[Index - 1]); + + // + // Append vendor class identify option + // + OptList[Index]->OpCode =3D PXEBC_DHCP4_TAG_CLASS_ID; + OptList[Index]->Length =3D (UINT8) sizeof (PXEBC_DHCP4_OPTION_CLID); + OptEnt.Clid =3D (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->= Data; + CopyMem ( + OptEnt.Clid, + DEFAULT_CLASS_ID_DATA, + sizeof (PXEBC_DHCP4_OPTION_CLID) + ); + PxeBcUintnToAscDecWithFormat ( + EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE, + OptEnt.Clid->ArchitectureType, + sizeof (OptEnt.Clid->ArchitectureType) + ); + + if (Private->Nii !=3D NULL) { + CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (O= ptEnt.Clid->InterfaceName)); + PxeBcUintnToAscDecWithFormat (Private->Nii->MajorVer, OptEnt.Clid->Und= iMajor, sizeof (OptEnt.Clid->UndiMajor)); + PxeBcUintnToAscDecWithFormat (Private->Nii->MinorVer, OptEnt.Clid->Und= iMinor, sizeof (OptEnt.Clid->UndiMinor)); + } + + Index++; + + return Index; +} + + +/** + Create a template DHCPv4 packet as a seed. + + @param[out] Seed Pointer to the seed packet. + @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL. + +**/ +VOID +PxeBcSeedDhcp4Packet ( + OUT EFI_DHCP4_PACKET *Seed, + IN EFI_UDP4_PROTOCOL *Udp4 + ) +{ + EFI_SIMPLE_NETWORK_MODE Mode; + EFI_DHCP4_HEADER *Header; + + // + // Get IfType and HwAddressSize from SNP mode data. + // + Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode); + + Seed->Size =3D sizeof (EFI_DHCP4_PACKET); + Seed->Length =3D sizeof (Seed->Dhcp4); + Header =3D &Seed->Dhcp4.Header; + ZeroMem (Header, sizeof (EFI_DHCP4_HEADER)); + Header->OpCode =3D PXEBC_DHCP4_OPCODE_REQUEST; + Header->HwType =3D Mode.IfType; + Header->HwAddrLen =3D (UINT8) Mode.HwAddressSize; + CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen); + + Seed->Dhcp4.Magik =3D PXEBC_DHCP4_MAGIC; + Seed->Dhcp4.Option[0] =3D PXEBC_DHCP4_TAG_EOP; +} + + +/** + Cache the DHCPv4 packet. + + @param[in] Dst Pointer to the cache buffer for DHCPv4 packet. + @param[in] Src Pointer to the DHCPv4 packet to be cached. + +**/ +VOID +PxeBcCacheDhcp4Packet ( + IN EFI_DHCP4_PACKET *Dst, + IN EFI_DHCP4_PACKET *Src + ) +{ + ASSERT (Dst->Size >=3D Src->Length); + + CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length); + Dst->Length =3D Src->Length; +} + + +/** + Parse the cached DHCPv4 packet, including all the options. + + @param[in] Cache4 Pointer to cached DHCPv4 packet. + + @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully. + @retval EFI_DEVICE_ERROR Failed to parse and invalid packet. + +**/ +EFI_STATUS +PxeBcParseDhcp4Packet ( + IN PXEBC_DHCP4_PACKET_CACHE *Cache4 + ) +{ + EFI_DHCP4_PACKET *Offer; + EFI_DHCP4_PACKET_OPTION **Options; + EFI_DHCP4_PACKET_OPTION *Option; + PXEBC_OFFER_TYPE OfferType; + UINTN Index; + BOOLEAN IsProxyOffer; + BOOLEAN IsPxeOffer; + UINT8 *Ptr8; + + IsProxyOffer =3D FALSE; + IsPxeOffer =3D FALSE; + + ZeroMem (Cache4->OptList, sizeof (Cache4->OptList)); + ZeroMem (&Cache4->VendorOpt, sizeof (Cache4->VendorOpt)); + + Offer =3D &Cache4->Packet.Offer; + Options =3D Cache4->OptList; + + // + // Parse DHCPv4 options in this offer, and store the pointers. + // First, try to parse DHCPv4 options from the DHCP optional parameters = field. + // + for (Index =3D 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) { + Options[Index] =3D PxeBcParseDhcp4Options ( + Offer->Dhcp4.Option, + GET_OPTION_BUFFER_LEN (Offer), + mInterestedDhcp4Tags[Index] + ); + } + // + // Second, Check if bootfilename and serverhostname is overloaded to car= ry DHCP options refers to rfc-2132.=20 + // If yes, try to parse options from the BootFileName field, then Server= Name field. + // + Option =3D Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD]; + if (Option !=3D NULL) { + if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE) !=3D 0) { + for (Index =3D 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) { + if (Options[Index] =3D=3D NULL) { + Options[Index] =3D PxeBcParseDhcp4Options ( + (UINT8 *) Offer->Dhcp4.Header.BootFileName, + sizeof (Offer->Dhcp4.Header.BootFileName), + mInterestedDhcp4Tags[Index] + ); + } + } + } + if ((Option->Data[0] & PXEBC_DHCP4_OVERLOAD_SERVER_NAME) !=3D 0) { + for (Index =3D 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) { + if (Options[Index] =3D=3D NULL) { + Options[Index] =3D PxeBcParseDhcp4Options ( + (UINT8 *) Offer->Dhcp4.Header.ServerName, + sizeof (Offer->Dhcp4.Header.ServerName), + mInterestedDhcp4Tags[Index] + ); + } + } + } + } + + // + // The offer with zero "yiaddr" is a proxy offer. + // + if (Offer->Dhcp4.Header.YourAddr.Addr[0] =3D=3D 0) { + IsProxyOffer =3D TRUE; + } + + // + // The offer with "PXEClient" is a PXE offer. + // + Option =3D Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID]; + if ((Option !=3D NULL) && (Option->Length >=3D 9) && + (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) =3D=3D 0)) { + IsPxeOffer =3D TRUE; + } + + // + // Parse PXE vendor options in this offer, and store the contents/pointe= rs. + // + Option =3D Options[PXEBC_DHCP4_TAG_INDEX_VENDOR]; + if (IsPxeOffer && Option !=3D NULL) { + PxeBcParseVendorOptions (Option, &Cache4->VendorOpt); + } + + // + // Parse PXE boot file name: + // According to PXE spec, boot file name should be read from DHCP option= 67 (bootfile name) if present. + // Otherwise, read from boot file field in DHCP header. + // + if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] !=3D NULL) { + // + // RFC 2132, Section 9.5 does not strictly state Bootfile name (option= 67) is null + // terminated string. So force to append null terminated character at = the end of string. + // + Ptr8 =3D (UINT8*)&Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data[0]; + Ptr8 +=3D Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Length; + if (*(Ptr8 - 1) !=3D '\0') { + *Ptr8 =3D '\0'; + } + } else if (Offer->Dhcp4.Header.BootFileName[0] !=3D 0) { + // + // If the bootfile is not present and bootfilename is present in DHCPv= 4 packet, just parse it. + // Do not count dhcp option header here, or else will destroy the serv= erhostname. + // + Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] =3D (EFI_DHCP4_PACKET_OPTION *= ) + (&Offer->Dhcp4.Header.Boot= FileName[0] - + OFFSET_OF (EFI_DHCP4_PACKE= T_OPTION, Data[0])); + + } + + // + // Determine offer type of the DHCPv4 packet. + // + Option =3D Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE]; + if (Option =3D=3D NULL || Option->Data[0] =3D=3D 0) { + // + // It's a Bootp offer. + // + OfferType =3D PxeOfferTypeBootp; + + Option =3D Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]; + if (Option =3D=3D NULL) { + // + // If the Bootp offer without bootfilename, discard it. + // + return EFI_DEVICE_ERROR; + } + } else { + + if (IS_VALID_DISCOVER_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) { + // + // It's a PXE10 offer with PXEClient and discover vendor option. + // + OfferType =3D IsProxyOffer ? PxeOfferTypeProxyPxe10 : PxeOfferTypeDh= cpPxe10; + } else if (IS_VALID_MTFTP_VENDOR_OPTION (Cache4->VendorOpt.BitMap)) { + // + // It's a WFM11a offer with PXEClient and mtftp vendor option. + // But multi-cast download is not supported currently, so discard it= . + // + return EFI_DEVICE_ERROR; + } else if (IsPxeOffer) { + // + // It's a BINL offer only with PXEClient. + // + OfferType =3D IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhc= pBinl; + } else { + // + // It's a DHCPv4 only offer, which is a pure DHCPv4 offer packet. + // + OfferType =3D PxeOfferTypeDhcpOnly; + } + } + + Cache4->OfferType =3D OfferType; + + return EFI_SUCCESS; +} + + +/** + Cache the DHCPv4 ack packet, and parse it on demand. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Ack Pointer to the DHCPv4 ack packet. + @param[in] Verified If TRUE, parse the ACK packet and store = info into mode data. + +**/ +VOID +PxeBcCopyDhcp4Ack ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP4_PACKET *Ack, + IN BOOLEAN Verified + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + + Mode =3D Private->PxeBc.Mode; + + PxeBcCacheDhcp4Packet (&Private->DhcpAck.Dhcp4.Packet.Ack, Ack); + + if (Verified) { + // + // Parse the ack packet and store it into mode data if needed. + // + PxeBcParseDhcp4Packet (&Private->DhcpAck.Dhcp4); + CopyMem (&Mode->DhcpAck.Dhcpv4, &Ack->Dhcp4, Ack->Length); + Mode->DhcpAckReceived =3D TRUE; + } +} + + +/** + Cache the DHCPv4 proxy offer packet according to the received order. + + @param[in] Private Pointer to PxeBc private data. + @param[in] OfferIndex The received order of offer packets. + +**/ +VOID +PxeBcCopyProxyOffer ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 OfferIndex + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_DHCP4_PACKET *Offer; + + ASSERT (OfferIndex < Private->OfferNum); + ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM); + + Mode =3D Private->PxeBc.Mode; + Offer =3D &Private->OfferBuffer[OfferIndex].Dhcp4.Packet.Offer; + + // + // Cache the proxy offer packet and parse it. + // + PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Offer); + PxeBcParseDhcp4Packet (&Private->ProxyOffer.Dhcp4); + + // + // Store this packet into mode data. + // + CopyMem (&Mode->ProxyOffer.Dhcpv4, &Offer->Dhcp4, Offer->Length); + Mode->ProxyOfferReceived =3D TRUE; +} + + +/** + Retry to request bootfile name by the BINL offer. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Index The received order of offer packets. + + @retval EFI_SUCCESS Successfully retried to request bootfil= e name. + @retval EFI_DEVICE_ERROR Failed to retry bootfile name. + +**/ +EFI_STATUS +PxeBcRetryBinlOffer ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 Index + ) +{ + EFI_DHCP4_PACKET *Offer; + EFI_IP_ADDRESS ServerIp; + EFI_STATUS Status; + PXEBC_DHCP4_PACKET_CACHE *Cache4; + EFI_DHCP4_PACKET *Reply; + + ASSERT (Index < PXEBC_OFFER_MAX_NUM); + ASSERT (Private->OfferBuffer[Index].Dhcp4.OfferType =3D=3D PxeOfferTypeD= hcpBinl || + Private->OfferBuffer[Index].Dhcp4.OfferType =3D=3D PxeOfferTypeP= roxyBinl); + + Offer =3D &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; + + // + // Prefer to siaddr in header as next server address. If it's zero, then= use option 54. + // + if (Offer->Dhcp4.Header.ServerAddr.Addr[0] =3D=3D 0) { + CopyMem ( + &ServerIp.Addr[0], + Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_SERV= ER_ID]->Data, + sizeof (EFI_IPv4_ADDRESS) + ); + } else { + CopyMem ( + &ServerIp.Addr[0], + &Offer->Dhcp4.Header.ServerAddr, + sizeof (EFI_IPv4_ADDRESS) + ); + } + + Private->IsDoDiscover =3D FALSE; + Cache4 =3D &Private->ProxyOffer.Dhcp4; + Reply =3D &Cache4->Packet.Offer; + + // + // Send another request packet for bootfile name. + // + Status =3D PxeBcDhcp4Discover ( + Private, + 0, + NULL, + FALSE, + &ServerIp, + 0, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Parse the reply for the last request packet. + // + Status =3D PxeBcParseDhcp4Packet (Cache4); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Cache4->OfferType !=3D PxeOfferTypeProxyPxe10 && + Cache4->OfferType !=3D PxeOfferTypeProxyWfm11a && + Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] =3D=3D NULL) { + // + // This BINL ack doesn't have discovery option set or multicast option= set + // or bootfile name specified. + // + return EFI_DEVICE_ERROR; + } + + // + // Store the reply into mode data. + // + Private->PxeBc.Mode->ProxyOfferReceived =3D TRUE; + CopyMem (&Private->PxeBc.Mode->ProxyOffer.Dhcpv4, &Reply->Dhcp4, Reply->= Length); + + return EFI_SUCCESS; +} + + +/** + Cache all the received DHCPv4 offers, and set OfferIndex and OfferCount. + + @param[in] Private Pointer to PxeBc private data. + @param[in] RcvdOffer Pointer to the received offer packet. + +**/ +VOID +PxeBcCacheDhcp4Offer ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP4_PACKET *RcvdOffer + ) +{ + PXEBC_DHCP4_PACKET_CACHE *Cache4; + EFI_DHCP4_PACKET *Offer; + PXEBC_OFFER_TYPE OfferType; + + ASSERT (Private->OfferNum < PXEBC_OFFER_MAX_NUM); + Cache4 =3D &Private->OfferBuffer[Private->OfferNum].Dhcp4; + Offer =3D &Cache4->Packet.Offer; + + // + // Cache the content of DHCPv4 packet firstly. + // + PxeBcCacheDhcp4Packet (Offer, RcvdOffer); + + // + // Validate the DHCPv4 packet, and parse the options and offer type. + // + if (EFI_ERROR (PxeBcParseDhcp4Packet (Cache4))) { + return; + } + + // + // Determine whether cache the current offer by type, and record OfferIn= dex and OfferCount. + // + OfferType =3D Cache4->OfferType; + ASSERT (OfferType < PxeOfferTypeMax); + + if (OfferType =3D=3D PxeOfferTypeBootp) { + // + // It's a Bootp offer, only cache the first one, and discard the other= s. + // + if (Private->OfferCount[OfferType] =3D=3D 0) { + Private->OfferIndex[OfferType][0] =3D Private->OfferNum; + Private->OfferCount[OfferType] =3D 1; + } else { + return; + } + } else { + ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM); + if (IS_PROXY_DHCP_OFFER (Offer)) { + // + // It's a proxy offer without yiaddr, including PXE10, WFM11a or BIN= L offer. + // + Private->IsProxyRecved =3D TRUE; + + if (OfferType =3D=3D PxeOfferTypeProxyBinl) { + // + // Cache all proxy BINL offers. + // + Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] =3D= Private->OfferNum; + Private->OfferCount[OfferType]++; + } else if (Private->OfferCount[OfferType] > 0) { + // + // Only cache the first PXE10/WFM11a offer, and discard the others= . + // + Private->OfferIndex[OfferType][0] =3D Private->OfferNum; + Private->OfferCount[OfferType] =3D 1; + } else { + return ; + } + } else { + // + // It's a DHCPv4 offer with yiaddr, and cache them all. + // + Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] =3D P= rivate->OfferNum; + Private->OfferCount[OfferType]++; + } + } + + Private->OfferNum++; +} + + +/** + Select an DHCPv4 offer, and record SelectIndex and SelectProxyType. + + @param[in] Private Pointer to PxeBc private data. + +**/ +VOID +PxeBcSelectDhcp4Offer ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + UINT32 Index; + UINT32 OfferIndex; + EFI_DHCP4_PACKET *Offer; + + Private->SelectIndex =3D 0; + + if (Private->IsOfferSorted) { + // + // Select offer by default policy. + // + if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) { + // + // 1. DhcpPxe10 offer + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpPxe10][= 0] + 1; + + } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) { + // + // 2. DhcpWfm11a offer + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpWfm11a]= [0] + 1; + + } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && + Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) { + // + // 3. DhcpOnly offer and ProxyPxe10 offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnl= y][0] + 1; + Private->SelectProxyType =3D PxeOfferTypeProxyPxe10; + + } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && + Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) { + // + // 4. DhcpOnly offer and ProxyWfm11a offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnl= y][0] + 1; + Private->SelectProxyType =3D PxeOfferTypeProxyWfm11a; + + } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) { + // + // 5. DhcpBinl offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpBinl][0= ] + 1; + + } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && + Private->OfferCount[PxeOfferTypeProxyBinl] > 0) { + // + // 6. DhcpOnly offer and ProxyBinl offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnl= y][0] + 1; + Private->SelectProxyType =3D PxeOfferTypeProxyBinl; + + } else { + // + // 7. DhcpOnly offer with bootfilename. + // + for (Index =3D 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly];= Index++) { + OfferIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnly][Index]; + if (Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG= _INDEX_BOOTFILE] !=3D NULL) { + Private->SelectIndex =3D OfferIndex + 1; + break; + } + } + // + // 8. Bootp offer with bootfilename. + // + OfferIndex =3D Private->OfferIndex[PxeOfferTypeBootp][0]; + if (Private->SelectIndex =3D=3D 0 && + Private->OfferCount[PxeOfferTypeBootp] > 0 && + Private->OfferBuffer[OfferIndex].Dhcp4.OptList[PXEBC_DHCP4_TAG_I= NDEX_BOOTFILE] !=3D NULL) { + Private->SelectIndex =3D OfferIndex + 1; + } + } + } else { + // + // Select offer by received order. + // + for (Index =3D 0; Index < Private->OfferNum; Index++) { + + Offer =3D &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; + + if (IS_PROXY_DHCP_OFFER (Offer)) { + // + // Skip proxy offers + // + continue; + } + + if (!Private->IsProxyRecved && + Private->OfferBuffer[Index].Dhcp4.OfferType =3D=3D PxeOfferTypeD= hcpOnly && + Private->OfferBuffer[Index].Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_= BOOTFILE] =3D=3D NULL) { + // + // Skip if DhcpOnly offer without any other proxy offers or bootfi= lename. + // + continue; + } + + // + // Record the index of the select offer. + // + Private->SelectIndex =3D Index + 1; + break; + } + } +} + + +/** + Handle the DHCPv4 offer packet. + + @param[in] Private Pointer to PxeBc private data. + + @retval EFI_SUCCESS Handled the DHCPv4 offer packet successf= ully. + @retval EFI_NO_RESPONSE No response to the following request pac= ket. + @retval EFI_NOT_FOUND No boot filename received. + +**/ +EFI_STATUS +PxeBcHandleDhcp4Offer ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + PXEBC_DHCP4_PACKET_CACHE *Cache4; + EFI_DHCP4_PACKET_OPTION **Options; + UINT32 Index; + EFI_DHCP4_PACKET *Offer; + PXEBC_OFFER_TYPE OfferType; + UINT32 ProxyIndex; + UINT32 SelectIndex; + EFI_STATUS Status; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_DHCP4_PACKET *Ack; + + ASSERT (Private->SelectIndex > 0); + SelectIndex =3D (UINT32) (Private->SelectIndex - 1); + ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); + Cache4 =3D &Private->OfferBuffer[SelectIndex].Dhcp4; + Options =3D Cache4->OptList; + Status =3D EFI_SUCCESS; + + if (Cache4->OfferType =3D=3D PxeOfferTypeDhcpBinl) { + // + // DhcpBinl offer is selected, so need try to request bootfilename by = this offer. + // + if (EFI_ERROR (PxeBcRetryBinlOffer (Private, SelectIndex))) { + Status =3D EFI_NO_RESPONSE; + } + } else if (Cache4->OfferType =3D=3D PxeOfferTypeDhcpOnly) { + + if (Private->IsProxyRecved) { + // + // DhcpOnly offer is selected, so need try to request bootfile name. + // + ProxyIndex =3D 0; + if (Private->IsOfferSorted) { + // + // The proxy offer should be determined if select by default polic= y. + // IsOfferSorted means all offers are labeled by OfferIndex. + // + ASSERT (Private->SelectProxyType < PxeOfferTypeMax); + ASSERT (Private->OfferCount[Private->SelectProxyType] > 0); + + if (Private->SelectProxyType =3D=3D PxeOfferTypeProxyBinl) { + // + // Try all the cached ProxyBinl offer one by one to request boot= file name. + // + for (Index =3D 0; Index < Private->OfferCount[Private->SelectPro= xyType]; Index++) { + ASSERT (Index < PXEBC_OFFER_MAX_NUM); + ProxyIndex =3D Private->OfferIndex[Private->SelectProxyType][I= ndex]; + if (!EFI_ERROR (PxeBcRetryBinlOffer (Private, ProxyIndex))) { + break; + } + } + if (Index =3D=3D Private->OfferCount[Private->SelectProxyType]) = { + Status =3D EFI_NO_RESPONSE; + } + } else { + // + // For other proxy offers, only one is buffered. + // + ProxyIndex =3D Private->OfferIndex[Private->SelectProxyType][0]; + } + } else { + // + // The proxy offer should not be determined if select by received = order. + // + Status =3D EFI_NO_RESPONSE; + + for (Index =3D 0; Index < Private->OfferNum; Index++) { + ASSERT (Index < PXEBC_OFFER_MAX_NUM); + Offer =3D &Private->OfferBuffer[Index].Dhcp4.Packet.Offer; + OfferType =3D Private->OfferBuffer[Index].Dhcp4.OfferType; + if (!IS_PROXY_DHCP_OFFER (Offer)) { + // + // Skip non proxy DHCPv4 offers. + // + continue; + } + + if (OfferType =3D=3D PxeOfferTypeProxyBinl) { + // + // Try all the cached ProxyBinl offer one by one to request bo= otfile name. + // + if (EFI_ERROR (PxeBcRetryBinlOffer (Private, Index))) { + continue; + } + } + + Private->SelectProxyType =3D OfferType; + ProxyIndex =3D Index; + Status =3D EFI_SUCCESS; + break; + } + } + + if (!EFI_ERROR (Status) && Private->SelectProxyType !=3D PxeOfferTyp= eProxyBinl) { + // + // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer,= copy and parse it. + // + PxeBcCopyProxyOffer (Private, ProxyIndex); + } + } else { + // + // Othewise, the bootfile name must be included in DhcpOnly offer. + // + if (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] =3D=3D NULL) { + Status =3D EFI_NOT_FOUND; + } + } + } + + if (!EFI_ERROR (Status)) { + // + // All PXE boot information is ready by now. + // + Mode =3D Private->PxeBc.Mode; + Offer =3D &Cache4->Packet.Offer; + Ack =3D &Private->DhcpAck.Dhcp4.Packet.Ack; + if (Cache4->OfferType =3D=3D PxeOfferTypeBootp) { + // + // Bootp is a special case that only 2 packets involved instead of 4= . So the bootp's reply + // should be taken as ack. + // + Ack =3D Offer; + } + + PxeBcCopyDhcp4Ack (Private, Ack, TRUE); + Mode->DhcpDiscoverValid =3D TRUE; + } + + return Status; +} + + +/** + EFI_DHCP4_CALLBACK is provided by the consumer of the EFI DHCPv4 Protoco= l driver + to intercept events that occurred in the configuration process. + + @param[in] This Pointer to the EFI DHCPv4 Protocol. + @param[in] Context Pointer to the context set by EFI_DHCP4_PR= OTOCOL.Configure(). + @param[in] CurrentState The current operational state of the EFI D= HCPv4 Protocol driver. + @param[in] Dhcp4Event The event that occurs in the current state= , which usually means a + state transition. + @param[in] Packet The DHCPv4 packet that is going to be sent= or already received. + @param[out] NewPacket The packet that is used to replace the abo= ve Packet. + + @retval EFI_SUCCESS Tells the EFI DHCPv4 Protocol driver to co= ntinue the DHCP process. + @retval EFI_NOT_READY Only used in the Dhcp4Selecting state. The= EFI DHCPv4 Protocol + driver will continue to wait for more DHCP= OFFER packets until the + retry timeout expires. + @retval EFI_ABORTED Tells the EFI DHCPv4 Protocol driver to ab= ort the current process + and return to the Dhcp4Init or Dhcp4InitRe= boot state. + +**/ +EFI_STATUS +EFIAPI +PxeBcDhcp4CallBack ( + IN EFI_DHCP4_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP4_STATE CurrentState, + IN EFI_DHCP4_EVENT Dhcp4Event, + IN EFI_DHCP4_PACKET *Packet OPTIONAL, + OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; + EFI_DHCP4_PACKET_OPTION *MaxMsgSize; + UINT16 Value; + EFI_STATUS Status; + BOOLEAN Received; + + if ((Dhcp4Event !=3D Dhcp4RcvdOffer) && + (Dhcp4Event !=3D Dhcp4SelectOffer) && + (Dhcp4Event !=3D Dhcp4SendDiscover) && + (Dhcp4Event !=3D Dhcp4RcvdAck)) { + return EFI_SUCCESS; + } + + Private =3D (PXEBC_PRIVATE_DATA *) Context; + Mode =3D Private->PxeBc.Mode; + Callback =3D Private->PxeBcCallback; + + // + // Override the Maximum DHCP Message Size. + // + MaxMsgSize =3D PxeBcParseDhcp4Options ( + Packet->Dhcp4.Option, + GET_OPTION_BUFFER_LEN (Packet), + PXEBC_DHCP4_TAG_MAXMSG + ); + if (MaxMsgSize !=3D NULL) { + Value =3D HTONS (PXEBC_DHCP4_PACKET_MAX_SIZE - 8); + CopyMem (MaxMsgSize->Data, &Value, sizeof (Value)); + } + + // + // Callback to user if any packets sent or received. + // + if (Dhcp4Event !=3D Dhcp4SelectOffer && Callback !=3D NULL) { + Received =3D (BOOLEAN) (Dhcp4Event =3D=3D Dhcp4RcvdOffer || Dhcp4Event= =3D=3D Dhcp4RcvdAck); + Status =3D Callback->Callback ( + Callback, + Private->Function, + Received, + Packet->Length, + (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4 + ); + if (Status !=3D EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + return EFI_ABORTED; + } + } + + Status =3D EFI_SUCCESS; + + switch (Dhcp4Event) { + + case Dhcp4SendDiscover: + // + // Cache the DHCPv4 discover packet to mode data directly. + // It need to check SendGuid as well as Dhcp4SendRequest. + // + CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp4, Packet->Length); + + case Dhcp4SendRequest: + if (Mode->SendGUID) { + // + // Send the system Guid instead of the MAC address as the hardware a= ddress if required. + // + if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Packet->Dhcp4.Heade= r.ClientHwAddr))) { + // + // Zero the Guid to indicate NOT programable if failed to get syst= em Guid. + // + ZeroMem (Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID)); + } + Packet->Dhcp4.Header.HwAddrLen =3D (UINT8) sizeof (EFI_GUID); + } + break; + + case Dhcp4RcvdOffer: + Status =3D EFI_NOT_READY; + if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { + // + // Cache the DHCPv4 offers to OfferBuffer[] for select later, and re= cord + // the OfferIndex and OfferCount. + // + PxeBcCacheDhcp4Offer (Private, Packet); + } + break; + + case Dhcp4SelectOffer: + // + // Select offer by the default policy or by order, and record the Sele= ctIndex + // and SelectProxyType. + // + PxeBcSelectDhcp4Offer (Private); + + if (Private->SelectIndex =3D=3D 0) { + Status =3D EFI_ABORTED; + } else { + *NewPacket =3D &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp4= .Packet.Offer; + } + break; + + case Dhcp4RcvdAck: + // + // Cache the DHCPv4 ack to Private->Dhcp4Ack, but it's not the final a= ck in mode data + // without verification. + // + ASSERT (Private->SelectIndex !=3D 0); + + PxeBcCopyDhcp4Ack (Private, Packet, FALSE); + break; + + default: + break; + } + + return Status; +} + + +/** + Build and send out the request packet for the bootfile, and parse the re= ply. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Type PxeBc option boot item type. + @param[in] Layer Pointer to option boot item layer. + @param[in] UseBis Use BIS or not. + @param[in] DestIp Pointer to the server address. + @param[in] IpCount The total count of the server address. + @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST. + + @retval EFI_SUCCESS Successfully discovered boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover boot file. + +**/ +EFI_STATUS +PxeBcDhcp4Discover ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_IP_ADDRESS *DestIp, + IN UINT16 IpCount, + IN EFI_PXE_BASE_CODE_SRVLIST *SrvList + ) +{ + EFI_PXE_BASE_CODE_UDP_PORT Sport; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_DHCP4_PROTOCOL *Dhcp4; + EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token; + BOOLEAN IsBCast; + EFI_STATUS Status; + UINT16 RepIndex; + UINT16 SrvIndex; + UINT16 TryIndex; + EFI_DHCP4_LISTEN_POINT ListenPoint; + EFI_DHCP4_PACKET *Response; + UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE]; + EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM]= ; + UINT32 OptCount; + EFI_DHCP4_PACKET_OPTION *PxeOpt; + PXEBC_OPTION_BOOT_ITEM *PxeBootItem; + UINT8 VendorOptLen; + UINT32 Xid; + + Mode =3D Private->PxeBc.Mode; + Dhcp4 =3D Private->Dhcp4; + Status =3D EFI_SUCCESS; + + ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN)); + + // + // Use broadcast if destination address not specified. + // + if (DestIp =3D=3D NULL) { + Sport =3D PXEBC_DHCP4_S_PORT; + IsBCast =3D TRUE; + } else { + Sport =3D PXEBC_BS_DISCOVER_PORT; + IsBCast =3D FALSE; + } + + if (!UseBis && Layer !=3D NULL) { + *Layer &=3D EFI_PXE_BASE_CODE_BOOT_LAYER_MASK; + } + + // + // Build all the options for the request packet. + // + OptCount =3D PxeBcBuildDhcp4Options (Private, OptList, Buffer, TRUE); + + if (Private->IsDoDiscover) { + // + // Add vendor option of PXE_BOOT_ITEM + // + VendorOptLen =3D (UINT8) ((sizeof (EFI_DHCP4_PACKET_OPTION) - 1) = * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1); + OptList[OptCount] =3D AllocateZeroPool (VendorOptLen); + if (OptList[OptCount] =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + OptList[OptCount]->OpCode =3D PXEBC_DHCP4_TAG_VENDOR; + OptList[OptCount]->Length =3D (UINT8) (VendorOptLen - 2); + PxeOpt =3D (EFI_DHCP4_PACKET_OPTION *) OptList[= OptCount]->Data; + PxeOpt->OpCode =3D PXEBC_VENDOR_TAG_BOOT_ITEM; + PxeOpt->Length =3D (UINT8) sizeof (PXEBC_OPTION_BOOT_IT= EM); + PxeBootItem =3D (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->D= ata; + PxeBootItem->Type =3D HTONS (Type); + PxeOpt->Data[PxeOpt->Length] =3D PXEBC_DHCP4_TAG_EOP; + + if (Layer !=3D NULL) { + PxeBootItem->Layer =3D HTONS (*Layer); + } + + OptCount++; + } + + // + // Build the request packet with seed packet and option list. + // + Status =3D Dhcp4->Build ( + Dhcp4, + &Private->SeedPacket, + 0, + NULL, + OptCount, + OptList, + &Token.Packet + ); + // + // Free the vendor option of PXE_BOOT_ITEM. + // + if (Private->IsDoDiscover) { + FreePool (OptList[OptCount - 1]); + } + + if (EFI_ERROR (Status)) { + return Status; + } + + if (Mode->SendGUID) { + if (EFI_ERROR (NetLibGetSystemGuid ((EFI_GUID *) Token.Packet->Dhcp4.H= eader.ClientHwAddr))) { + // + // Zero the Guid to indicate NOT programable if failed to get system= Guid. + // + ZeroMem (Token.Packet->Dhcp4.Header.ClientHwAddr, sizeof (EFI_GUID))= ; + } + Token.Packet->Dhcp4.Header.HwAddrLen =3D (UINT8) sizeof (EFI_GUID); + } + + // + // Set fields of the token for the request packet. + // + Xid =3D NET_RANDOM (NetRandomInitSeed ()= ); + Token.Packet->Dhcp4.Header.Xid =3D HTONL (Xid); + Token.Packet->Dhcp4.Header.Reserved =3D HTONS ((UINT16) ((IsBCast) ? 0x8= 000 : 0x0)); + CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, si= zeof (EFI_IPv4_ADDRESS)); + + Token.RemotePort =3D Sport; + + if (IsBCast) { + SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff); + } else { + CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS)); + } + + CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_AD= DRESS)); + + if (!IsBCast) { + Token.ListenPointCount =3D 1; + Token.ListenPoints =3D &ListenPoint; + Token.ListenPoints[0].ListenPort =3D PXEBC_BS_DISCOVER_PORT; + CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, si= zeof(EFI_IPv4_ADDRESS)); + CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, size= of(EFI_IPv4_ADDRESS)); + } + + // + // Send out the request packet to discover the bootfile. + // + for (TryIndex =3D 1; TryIndex <=3D PXEBC_BOOT_REQUEST_RETRIES; TryIndex+= +) { + + Token.TimeoutValue =3D (UINT16) (PXEBC_BOOT_REQUEST_T= IMEOUT * TryIndex); + Token.Packet->Dhcp4.Header.Seconds =3D (UINT16) (PXEBC_BOOT_REQUEST_T= IMEOUT * (TryIndex - 1)); + + Status =3D Dhcp4->TransmitReceive (Dhcp4, &Token); + if (Token.Status !=3D EFI_TIMEOUT) { + break; + } + } + + if (TryIndex > PXEBC_BOOT_REQUEST_RETRIES) { + // + // No server response our PXE request + // + Status =3D EFI_TIMEOUT; + } + + if (!EFI_ERROR (Status)) { + + RepIndex =3D 0; + SrvIndex =3D 0; + Response =3D Token.ResponseList; + // + // Find the right PXE Reply according to server address. + // + while (RepIndex < Token.ResponseCount) { + + while (SrvIndex < IpCount) { + if (SrvList[SrvIndex].AcceptAnyResponse) { + break; + } + if ((SrvList[SrvIndex].Type =3D=3D Type) && + EFI_IP4_EQUAL (&Response->Dhcp4.Header.ServerAddr, &SrvList[Sr= vIndex].IpAddr)) { + break; + } + SrvIndex++; + } + + if ((IpCount !=3D SrvIndex) || (IpCount =3D=3D 0)) { + break; + } + + SrvIndex =3D 0; + RepIndex++; + + Response =3D (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Si= ze); + } + + if (RepIndex < Token.ResponseCount) { + // + // Cache the right PXE reply packet here, set valid flag later. + // Especially for PXE discover packet, store it into mode data here. + // + if (Private->IsDoDiscover) { + PxeBcCacheDhcp4Packet (&Private->PxeReply.Dhcp4.Packet.Ack, Respon= se); + CopyMem (&Mode->PxeDiscover, &Token.Packet->Dhcp4, Token.Packet->L= ength); + } else { + PxeBcCacheDhcp4Packet (&Private->ProxyOffer.Dhcp4.Packet.Offer, Re= sponse); + } + } else { + // + // Not found the right PXE reply packet. + // + Status =3D EFI_NOT_FOUND; + } + if (Token.ResponseList !=3D NULL) { + FreePool (Token.ResponseList); + } + } + + FreePool (Token.Packet); + return Status; +} + +/** + Switch the Ip4 policy to static. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS The policy is already configured to stat= ic. + @retval Others Other error as indicated.. + +**/ +EFI_STATUS +PxeBcSetIp4Policy ( =20 + IN PXEBC_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; + EFI_IP4_CONFIG2_POLICY Policy; + UINTN DataSize; + + Ip4Config2 =3D Private->Ip4Config2; + DataSize =3D sizeof (EFI_IP4_CONFIG2_POLICY); + Status =3D Ip4Config2->GetData ( + Ip4Config2, + Ip4Config2DataTypePolicy, + &DataSize, + &Policy + ); + if (EFI_ERROR (Status)) { + return Status; + } + =20 + if (Policy !=3D Ip4Config2PolicyStatic) { + Policy =3D Ip4Config2PolicyStatic; + Status=3D Ip4Config2->SetData ( + Ip4Config2, + Ip4Config2DataTypePolicy, + sizeof (EFI_IP4_CONFIG2_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + return Status; + }=20 + } + + return EFI_SUCCESS; +} + +/** + Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other P= XE boot information. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL + + @retval EFI_SUCCESS The D.O.R.A process successfully finished. + @retval Others Failed to finish the D.O.R.A process. + +**/ +EFI_STATUS +PxeBcDhcp4Dora ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP4_PROTOCOL *Dhcp4 + ) +{ + EFI_PXE_BASE_CODE_MODE *PxeMode; + EFI_DHCP4_CONFIG_DATA Config; + EFI_DHCP4_MODE_DATA Mode; + EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_OPTION_MAX_NUM]; + UINT8 Buffer[PXEBC_DHCP4_OPTION_MAX_SIZE]; + UINT32 OptCount; + EFI_STATUS Status; + + ASSERT (Dhcp4 !=3D NULL); + + Status =3D EFI_SUCCESS; + PxeMode =3D Private->PxeBc.Mode; + + // + // Build option list for the request packet. + // + OptCount =3D PxeBcBuildDhcp4Options (Private, OptList, Buffer, FALSE); + ASSERT (OptCount> 0); + + ZeroMem (&Mode, sizeof (EFI_DHCP4_MODE_DATA)); + ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); + + Config.OptionCount =3D OptCount; + Config.OptionList =3D OptList; + Config.Dhcp4Callback =3D PxeBcDhcp4CallBack; + Config.CallbackContext =3D Private; + Config.DiscoverTryCount =3D PXEBC_DHCP_RETRIES; + Config.DiscoverTimeout =3D mPxeDhcpTimeout; + + // + // Configure the DHCPv4 instance for PXE boot. + // + Status =3D Dhcp4->Configure (Dhcp4, &Config); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Initialize the record fields for DHCPv4 offer in private data. + // + Private->IsProxyRecved =3D FALSE; + Private->OfferNum =3D 0; + ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); + ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); + + // + // Start DHCPv4 D.O.R.A. process to acquire IPv4 address. This may=20 + // have already been done, thus do not leave in error if the return + // code is EFI_ALREADY_STARTED. + // + Status =3D Dhcp4->Start (Dhcp4, NULL); + if (EFI_ERROR (Status) && Status !=3D EFI_ALREADY_STARTED) { + if (Status =3D=3D EFI_ICMP_ERROR) { + PxeMode->IcmpErrorReceived =3D TRUE; + } + goto ON_EXIT; + } + + // + // Get the acquired IPv4 address and store them. + // + Status =3D Dhcp4->GetModeData (Dhcp4, &Mode); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + ASSERT (Mode.State =3D=3D Dhcp4Bound); + + CopyMem (&Private->StationIp, &Mode.ClientAddress, sizeof (EFI_IPv4_ADDR= ESS)); + CopyMem (&Private->SubnetMask, &Mode.SubnetMask, sizeof (EFI_IPv4_ADDRES= S)); + CopyMem (&Private->GatewayIp, &Mode.RouterAddress, sizeof (EFI_IPv4_ADDR= ESS)); + CopyMem (&PxeMode->StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDR= ESS)); + CopyMem (&PxeMode->SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_AD= DRESS)); + + Status =3D PxeBcFlushStationIp (Private, &Private->StationIp, &Private->= SubnetMask); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Check the selected offer whether BINL retry is needed. + // + Status =3D PxeBcHandleDhcp4Offer (Private); + + AsciiPrint ("\n Station IP address is "); + + PxeBcShowIp4Addr (&Private->StationIp.v4); + AsciiPrint ("\n"); + +ON_EXIT: + if (EFI_ERROR (Status)) { + Dhcp4->Stop (Dhcp4); + Dhcp4->Configure (Dhcp4, NULL); + } else { + ZeroMem (&Config, sizeof (EFI_DHCP4_CONFIG_DATA)); + Dhcp4->Configure (Dhcp4, &Config); + Private->IsAddressOk =3D TRUE; + } + + return Status; +} diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcDhcp4.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/Networ= kPkg/UefiPxeBcDxe/PxeBcDhcp4.h new file mode 100644 index 0000000..cc2ff98 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcDhcp4.h @@ -0,0 +1,409 @@ +/** @file + Functions declaration related with DHCPv4 for UefiPxeBc Driver. + + Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __EFI_PXEBC_DHCP4_H__ +#define __EFI_PXEBC_DHCP4_H__ + +#define PXEBC_DHCP4_OPTION_MAX_NUM 16 +#define PXEBC_DHCP4_OPTION_MAX_SIZE 312 +#define PXEBC_DHCP4_PACKET_MAX_SIZE 1472 +#define PXEBC_DHCP4_S_PORT 67 +#define PXEBC_DHCP4_C_PORT 68 +#define PXEBC_BS_DOWNLOAD_PORT 69 +#define PXEBC_BS_DISCOVER_PORT 4011 +#define PXEBC_DHCP4_OPCODE_REQUEST 1 +#define PXEBC_DHCP4_OPCODE_REPLY 2 +#define PXEBC_DHCP4_MSG_TYPE_REQUEST 3 +#define PXEBC_DHCP4_MAGIC 0x63538263 // network byte orde= r + +// +// Dhcp Options +// +#define PXEBC_DHCP4_TAG_PAD 0 // Pad Option +#define PXEBC_DHCP4_TAG_EOP 255 // End Option +#define PXEBC_DHCP4_TAG_NETMASK 1 // Subnet Mask +#define PXEBC_DHCP4_TAG_TIME_OFFSET 2 // Time Offset from UTC +#define PXEBC_DHCP4_TAG_ROUTER 3 // Router option, +#define PXEBC_DHCP4_TAG_TIME_SERVER 4 // Time Server +#define PXEBC_DHCP4_TAG_NAME_SERVER 5 // Name Server +#define PXEBC_DHCP4_TAG_DNS_SERVER 6 // Domain Name Server +#define PXEBC_DHCP4_TAG_HOSTNAME 12 // Host Name +#define PXEBC_DHCP4_TAG_BOOTFILE_LEN 13 // Boot File Size +#define PXEBC_DHCP4_TAG_DUMP 14 // Merit Dump File +#define PXEBC_DHCP4_TAG_DOMAINNAME 15 // Domain Name +#define PXEBC_DHCP4_TAG_ROOTPATH 17 // Root path +#define PXEBC_DHCP4_TAG_EXTEND_PATH 18 // Extensions Path +#define PXEBC_DHCP4_TAG_EMTU 22 // Maximum Datagram Reasse= mbly Size +#define PXEBC_DHCP4_TAG_TTL 23 // Default IP Time-to-live +#define PXEBC_DHCP4_TAG_BROADCAST 28 // Broadcast Address +#define PXEBC_DHCP4_TAG_NIS_DOMAIN 40 // Network Information Ser= vice Domain +#define PXEBC_DHCP4_TAG_NIS_SERVER 41 // Network Information Ser= vers +#define PXEBC_DHCP4_TAG_NTP_SERVER 42 // Network Time Protocol S= ervers +#define PXEBC_DHCP4_TAG_VENDOR 43 // Vendor Specific Informa= tion +#define PXEBC_DHCP4_TAG_REQUEST_IP 50 // Requested IP Address +#define PXEBC_DHCP4_TAG_LEASE 51 // IP Address Lease Time +#define PXEBC_DHCP4_TAG_OVERLOAD 52 // Option Overload +#define PXEBC_DHCP4_TAG_MSG_TYPE 53 // DHCP Message Type +#define PXEBC_DHCP4_TAG_SERVER_ID 54 // Server Identifier +#define PXEBC_DHCP4_TAG_PARA_LIST 55 // Parameter Request List +#define PXEBC_DHCP4_TAG_MAXMSG 57 // Maximum DHCP Message Si= ze +#define PXEBC_DHCP4_TAG_T1 58 // Renewal (T1) Time Value +#define PXEBC_DHCP4_TAG_T2 59 // Rebinding (T2) Time Val= ue +#define PXEBC_DHCP4_TAG_CLASS_ID 60 // Vendor class identifier +#define PXEBC_DHCP4_TAG_CLIENT_ID 61 // Client-identifier +#define PXEBC_DHCP4_TAG_TFTP 66 // TFTP server name +#define PXEBC_DHCP4_TAG_BOOTFILE 67 // Bootfile name +#define PXEBC_PXE_DHCP4_TAG_ARCH 93 +#define PXEBC_PXE_DHCP4_TAG_UNDI 94 +#define PXEBC_PXE_DHCP4_TAG_UUID 97 +// +// Sub-Options in Dhcp Vendor Option +// +#define PXEBC_VENDOR_TAG_MTFTP_IP 1 +#define PXEBC_VENDOR_TAG_MTFTP_CPORT 2 +#define PXEBC_VENDOR_TAG_MTFTP_SPORT 3 +#define PXEBC_VENDOR_TAG_MTFTP_TIMEOUT 4 +#define PXEBC_VENDOR_TAG_MTFTP_DELAY 5 +#define PXEBC_VENDOR_TAG_DISCOVER_CTRL 6 +#define PXEBC_VENDOR_TAG_DISCOVER_MCAST 7 +#define PXEBC_VENDOR_TAG_BOOT_SERVERS 8 +#define PXEBC_VENDOR_TAG_BOOT_MENU 9 +#define PXEBC_VENDOR_TAG_MENU_PROMPT 10 +#define PXEBC_VENDOR_TAG_MCAST_ALLOC 11 +#define PXEBC_VENDOR_TAG_CREDENTIAL_TYPES 12 +#define PXEBC_VENDOR_TAG_BOOT_ITEM 71 + +#define PXEBC_BOOT_REQUEST_TIMEOUT 1 +#define PXEBC_BOOT_REQUEST_RETRIES 4 + +#define PXEBC_DHCP4_OVERLOAD_FILE 1 +#define PXEBC_DHCP4_OVERLOAD_SERVER_NAME 2 + + +// +// The array index of the DHCP4 option tag interested +// +#define PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN 0 +#define PXEBC_DHCP4_TAG_INDEX_VENDOR 1 +#define PXEBC_DHCP4_TAG_INDEX_OVERLOAD 2 +#define PXEBC_DHCP4_TAG_INDEX_MSG_TYPE 3 +#define PXEBC_DHCP4_TAG_INDEX_SERVER_ID 4 +#define PXEBC_DHCP4_TAG_INDEX_CLASS_ID 5 +#define PXEBC_DHCP4_TAG_INDEX_BOOTFILE 6 +#define PXEBC_DHCP4_TAG_INDEX_MAX 7 + +// +// Dhcp4 and Dhcp6 share this definition, and corresponding +// relatioinship is as follows: +// +// Dhcp4Discover <> Dhcp6Solicit +// Dhcp4Offer <> Dhcp6Advertise +// Dhcp4Request <> Dhcp6Request +// Dhcp4Ack <> DHcp6Reply +// +typedef enum { + PxeOfferTypeDhcpOnly, + PxeOfferTypeDhcpPxe10, + PxeOfferTypeDhcpWfm11a, + PxeOfferTypeDhcpBinl, + PxeOfferTypeProxyPxe10, + PxeOfferTypeProxyWfm11a, + PxeOfferTypeProxyBinl, + PxeOfferTypeBootp, + PxeOfferTypeMax +} PXEBC_OFFER_TYPE; + +#define BIT(x) (1 << x) +#define CTRL(x) (0x1F & (x)) +#define DEFAULT_CLASS_ID_DATA "PXEClient:Arch:xxxxx:UNDI:003000" +#define DEFAULT_UNDI_TYPE 1 +#define DEFAULT_UNDI_MAJOR 3 +#define DEFAULT_UNDI_MINOR 0 + +#define MTFTP_VENDOR_OPTION_BIT_MAP \ + (BIT (PXEBC_VENDOR_TAG_MTFTP_IP) | \ + BIT (PXEBC_VENDOR_TAG_MTFTP_CPORT) | \ + BIT (PXEBC_VENDOR_TAG_MTFTP_SPORT) | \ + BIT (PXEBC_VENDOR_TAG_MTFTP_TIMEOUT) | \ + BIT (PXEBC_VENDOR_TAG_MTFTP_DELAY)) + +#define DISCOVER_VENDOR_OPTION_BIT_MAP \ + (BIT (PXEBC_VENDOR_TAG_DISCOVER_CTRL) | \ + BIT (PXEBC_VENDOR_TAG_DISCOVER_MCAST) | \ + BIT (PXEBC_VENDOR_TAG_BOOT_SERVERS) | \ + BIT (PXEBC_VENDOR_TAG_BOOT_MENU) | \ + BIT (PXEBC_VENDOR_TAG_MENU_PROMPT)) + +#define IS_VALID_BOOT_SERVERS(x) \ + ((((x)[0]) & BIT (PXEBC_VENDOR_TAG_BOOT_SERVERS)) \ + =3D=3D BIT (PXEBC_VENDOR_TAG_BOOT_SERVERS)) =20 + +#define IS_VALID_BOOT_PROMPT(x) \ + ((((x)[0]) & BIT (PXEBC_VENDOR_TAG_MENU_PROMPT)) \ + =3D=3D BIT (PXEBC_VENDOR_TAG_MENU_PROMPT)) + +#define IS_VALID_BOOT_MENU(x) \ + ((((x)[0]) & BIT (PXEBC_VENDOR_TAG_BOOT_MENU)) \ + =3D=3D BIT (PXEBC_VENDOR_TAG_BOOT_MENU)) + +#define IS_VALID_MTFTP_VENDOR_OPTION(x) \ + (((UINT32) ((x)[0]) & MTFTP_VENDOR_OPTION_BIT_MAP) \ + =3D=3D MTFTP_VENDOR_OPTION_BIT_MAP) + +#define IS_VALID_DISCOVER_VENDOR_OPTION(x) \ + (((UINT32) ((x)[0]) & DISCOVER_VENDOR_OPTION_BIT_MAP) !=3D 0) + +#define IS_VALID_CREDENTIAL_VENDOR_OPTION(x) \ + (((UINT32) ((x)[0]) & BIT (PXEBC_VENDOR_TAG_CREDENTIAL_TYPES)) \ + =3D=3D BIT (PXEBC_VENDOR_TAG_CREDENTIAL_TYPES)) + +#define IS_VALID_BOOTITEM_VENDOR_OPTION(x) \ + (((UINT32) ((x)[PXEBC_VENDOR_TAG_BOOT_ITEM / 32]) & \ + BIT (PXEBC_VENDOR_TAG_BOOT_ITEM % 32)) \ + =3D=3D BIT (PXEBC_VENDOR_TAG_BOOT_ITEM % 32)) + +#define SET_VENDOR_OPTION_BIT_MAP(x, y) \ + (*(x + ((y) / 32)) =3D (UINT32) ((UINT32) ((x)[(y) / 32]) | BIT ((y) % 3= 2))) + +#define GET_NEXT_DHCP_OPTION(Opt) \ + (EFI_DHCP4_PACKET_OPTION *) ((UINT8 *) (Opt) + \ + sizeof (EFI_DHCP4_PACKET_OPTION) + (Opt)->Length - 1) + +#define GET_OPTION_BUFFER_LEN(Pkt) \ + ((Pkt)->Length - sizeof (EFI_DHCP4_HEADER) - 4) + +#define GET_NEXT_BOOT_SVR_ENTRY(Ent) \ + (PXEBC_BOOT_SVR_ENTRY *) ((UINT8 *) Ent + sizeof (*(Ent)) + \ + ((Ent)->IpCnt - 1) * sizeof (EFI_IPv4_ADDRESS)) + +#define IS_PROXY_DHCP_OFFER(Offer) \ + EFI_IP4_EQUAL (&(Offer)->Dhcp4.Header.YourAddr, &mZeroIp4Addr) + +#define IS_DISABLE_BCAST_DISCOVER(x) \ + (((x) & BIT (0)) =3D=3D BIT (0)) + +#define IS_DISABLE_MCAST_DISCOVER(x) \ + (((x) & BIT (1)) =3D=3D BIT (1)) + +#define IS_ENABLE_USE_SERVER_LIST(x) \ + (((x) & BIT (2)) =3D=3D BIT (2)) + +#define IS_DISABLE_PROMPT_MENU(x) \ + (((x) & BIT (3)) =3D=3D BIT (3)) + + +#pragma pack(1) +typedef struct { + UINT8 ParaList[135]; +} PXEBC_DHCP4_OPTION_PARA; + +typedef struct { + UINT16 Size; +} PXEBC_DHCP4_OPTION_MAX_MESG_SIZE; + +typedef struct { + UINT8 Type; + UINT8 MajorVer; + UINT8 MinorVer; +} PXEBC_DHCP4_OPTION_UNDI; + +typedef struct { + UINT8 Type; +} PXEBC_DHCP4_OPTION_MESG; + +typedef struct { + UINT16 Type; +} PXEBC_DHCP4_OPTION_ARCH; + +typedef struct { + UINT8 ClassIdentifier[10]; + UINT8 ArchitecturePrefix[5]; + UINT8 ArchitectureType[5]; + UINT8 Lit3[1]; + UINT8 InterfaceName[4]; + UINT8 Lit4[1]; + UINT8 UndiMajor[3]; + UINT8 UndiMinor[3]; +} PXEBC_DHCP4_OPTION_CLID; + +typedef struct { + UINT8 Type; + UINT8 Guid[16]; +} PXEBC_DHCP4_OPTION_UUID; + +typedef struct { + UINT16 Type; + UINT16 Layer; +} PXEBC_OPTION_BOOT_ITEM; + +#pragma pack() + +typedef union { + PXEBC_DHCP4_OPTION_PARA *Para; + PXEBC_DHCP4_OPTION_UNDI *Undi; + PXEBC_DHCP4_OPTION_ARCH *Arch; + PXEBC_DHCP4_OPTION_CLID *Clid; + PXEBC_DHCP4_OPTION_UUID *Uuid; + PXEBC_DHCP4_OPTION_MESG *Mesg; + PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *MaxMesgSize; +} PXEBC_DHCP4_OPTION_ENTRY; + +#pragma pack(1) +typedef struct { + UINT16 Type; + UINT8 IpCnt; + EFI_IPv4_ADDRESS IpAddr[1]; +} PXEBC_BOOT_SVR_ENTRY; + +typedef struct { + UINT16 Type; + UINT8 DescLen; + UINT8 DescStr[1]; +} PXEBC_BOOT_MENU_ENTRY; + +typedef struct { + UINT8 Timeout; + UINT8 Prompt[1]; +} PXEBC_MENU_PROMPT; +#pragma pack() + +typedef struct { + UINT32 BitMap[8]; + EFI_IPv4_ADDRESS MtftpIp; + UINT16 MtftpCPort; + UINT16 MtftpSPort; + UINT8 MtftpTimeout; + UINT8 MtftpDelay; + UINT8 DiscoverCtrl; + EFI_IPv4_ADDRESS DiscoverMcastIp; + EFI_IPv4_ADDRESS McastIpBase; + UINT16 McastIpBlock; + UINT16 McastIpRange; + UINT16 BootSrvType; + UINT16 BootSrvLayer; + PXEBC_BOOT_SVR_ENTRY *BootSvr; + UINT8 BootSvrLen; + PXEBC_BOOT_MENU_ENTRY *BootMenu; + UINT8 BootMenuLen; + PXEBC_MENU_PROMPT *MenuPrompt; + UINT8 MenuPromptLen; + UINT32 *CredType; + UINT8 CredTypeLen; +} PXEBC_VENDOR_OPTION; + +typedef union { + EFI_DHCP4_PACKET Offer; + EFI_DHCP4_PACKET Ack; + UINT8 Buffer[PXEBC_DHCP4_PACKET_MAX_SIZE]; +} PXEBC_DHCP4_PACKET; + +typedef struct { + PXEBC_DHCP4_PACKET Packet; + PXEBC_OFFER_TYPE OfferType; + EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_TAG_INDEX_MAX]; + PXEBC_VENDOR_OPTION VendorOpt; +} PXEBC_DHCP4_PACKET_CACHE; + + +/** + Create a template DHCPv4 packet as a seed. + + @param[out] Seed Pointer to the seed packet. + @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL. + +**/ +VOID +PxeBcSeedDhcp4Packet ( + OUT EFI_DHCP4_PACKET *Seed, + IN EFI_UDP4_PROTOCOL *Udp4 + ); + + +/** + Parse the cached DHCPv4 packet, including all the options. + + @param[in] Cache4 Pointer to cached DHCPv4 packet. + + @retval EFI_SUCCESS Parsed the DHCPv4 packet successfully. + @retval EFI_DEVICE_ERROR Failed to parse and invalid packet. + +**/ +EFI_STATUS +PxeBcParseDhcp4Packet ( + IN PXEBC_DHCP4_PACKET_CACHE *Cache4 + ); + + +/** + Build and send out the request packet for the bootfile, and parse the re= ply. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Type PxeBc option boot item type. + @param[in] Layer Pointer to option boot item layer. + @param[in] UseBis Use BIS or not. + @param[in] DestIp Pointer to the server address. + @param[in] IpCount The total count of the server address. + @param[in] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST. + + @retval EFI_SUCCESS Successfully discovered boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover boot file. + +**/ +EFI_STATUS +PxeBcDhcp4Discover ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_IP_ADDRESS *DestIp, + IN UINT16 IpCount, + IN EFI_PXE_BASE_CODE_SRVLIST *SrvList + ); + +/** + Switch the Ip4 policy to static. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS The policy is already configured to stat= ic. + @retval Others Other error as indicated.. + +**/ +EFI_STATUS +PxeBcSetIp4Policy ( =20 + IN PXEBC_PRIVATE_DATA *Private + ); + + +/** + Start the D.O.R.A DHCPv4 process to acquire the IPv4 address and other P= XE boot information. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Dhcp4 Pointer to the EFI_DHCP4_PROTOCOL + + @retval EFI_SUCCESS The D.O.R.A process successfully finished. + @retval Others Failed to finish the D.O.R.A process. + +**/ +EFI_STATUS +PxeBcDhcp4Dora ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP4_PROTOCOL *Dhcp4 + ); + +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcDhcp6.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Networ= kPkg/UefiPxeBcDxe/PxeBcDhcp6.c new file mode 100644 index 0000000..b1b1fb8 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcDhcp6.c @@ -0,0 +1,2096 @@ +/** @file + Functions implementation related with DHCPv6 for UefiPxeBc Driver. + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + +// +// Well-known multi-cast address defined in section-24.1 of rfc-3315 +// +// ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2 +// +EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress =3D {{0xFF, 2, 0, 0, 0, = 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}}; + +/** + Parse out a DHCPv6 option by OptTag, and find the position in buffer. + + @param[in] Buffer The pointer to the option buffer. + @param[in] Length Length of the option buffer. + @param[in] OptTag The required option tag. + + @retval NULL Failed to parse the required option. + @retval Others The postion of the required option in buffer. + +**/ +EFI_DHCP6_PACKET_OPTION * +PxeBcParseDhcp6Options ( + IN UINT8 *Buffer, + IN UINT32 Length, + IN UINT16 OptTag + ) +{ + EFI_DHCP6_PACKET_OPTION *Option; + UINT32 Offset; + + Option =3D (EFI_DHCP6_PACKET_OPTION *) Buffer; + Offset =3D 0; + + // + // OpLen and OpCode here are both stored in network order. + // + while (Offset < Length) { + + if (NTOHS (Option->OpCode) =3D=3D OptTag) { + + return Option; + } + + Offset +=3D (NTOHS(Option->OpLen) + 4); + Option =3D (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset); + } + + return NULL; +} + + +/** + Build the options buffer for the DHCPv6 request packet. + + @param[in] Private The pointer to PxeBc private data. + @param[out] OptList The pointer to the option pointer array. + @param[in] Buffer The pointer to the buffer to contain the= option list. + + @return Index The count of the built-in options. + +**/ +UINT32 +PxeBcBuildDhcp6Options ( + IN PXEBC_PRIVATE_DATA *Private, + OUT EFI_DHCP6_PACKET_OPTION **OptList, + IN UINT8 *Buffer + ) +{ + PXEBC_DHCP6_OPTION_ENTRY OptEnt; + UINT32 Index; + UINT16 Value; + + Index =3D 0; + OptList[0] =3D (EFI_DHCP6_PACKET_OPTION *) Buffer; + + // + // Append client option request option + // + OptList[Index]->OpCode =3D HTONS (PXEBC_DHCP6_OPT_ORO); + OptList[Index]->OpLen =3D HTONS (4); + OptEnt.Oro =3D (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]= ->Data; + OptEnt.Oro->OpCode[0] =3D HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL); + OptEnt.Oro->OpCode[1] =3D HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM); + Index++; + OptList[Index] =3D GET_NEXT_DHCP6_OPTION (OptList[Index - 1]= ); + + // + // Append client network device interface option + // + OptList[Index]->OpCode =3D HTONS (PXEBC_DHCP6_OPT_UNDI); + OptList[Index]->OpLen =3D HTONS ((UINT16)3); + OptEnt.Undi =3D (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index= ]->Data; + + if (Private->Nii !=3D NULL) { + OptEnt.Undi->Type =3D Private->Nii->Type; + OptEnt.Undi->MajorVer =3D Private->Nii->MajorVer; + OptEnt.Undi->MinorVer =3D Private->Nii->MinorVer; + } else { + OptEnt.Undi->Type =3D DEFAULT_UNDI_TYPE; + OptEnt.Undi->MajorVer =3D DEFAULT_UNDI_MAJOR; + OptEnt.Undi->MinorVer =3D DEFAULT_UNDI_MINOR; + } + + Index++; + OptList[Index] =3D GET_NEXT_DHCP6_OPTION (OptList[Index - 1]= ); + + // + // Append client system architecture option + // + OptList[Index]->OpCode =3D HTONS (PXEBC_DHCP6_OPT_ARCH); + OptList[Index]->OpLen =3D HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTIO= N_ARCH)); + OptEnt.Arch =3D (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index= ]->Data; + Value =3D HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE= ); + CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16)); + Index++; + OptList[Index] =3D GET_NEXT_DHCP6_OPTION (OptList[Index - 1]= ); + + // + // Append vendor class option to store the PXE class identifier. + // + OptList[Index]->OpCode =3D HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS); + OptList[Index]->OpLen =3D HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPT= ION_VENDOR_CLASS)); + OptEnt.VendorClass =3D (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) Opt= List[Index]->Data; + OptEnt.VendorClass->Vendor =3D HTONL (PXEBC_DHCP6_ENTERPRISE_NUM); + OptEnt.VendorClass->ClassLen =3D HTONS ((UINT16) sizeof (PXEBC_CLASS_ID)= ); + CopyMem ( + &OptEnt.VendorClass->ClassId, + DEFAULT_CLASS_ID_DATA, + sizeof (PXEBC_CLASS_ID) + ); + PxeBcUintnToAscDecWithFormat ( + EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE, + OptEnt.VendorClass->ClassId.ArchitectureType, + sizeof (OptEnt.VendorClass->ClassId.ArchitectureType) + ); + + if (Private->Nii !=3D NULL) { + CopyMem ( + OptEnt.VendorClass->ClassId.InterfaceName, + Private->Nii->StringId, + sizeof (OptEnt.VendorClass->ClassId.InterfaceName) + ); + PxeBcUintnToAscDecWithFormat ( + Private->Nii->MajorVer, + OptEnt.VendorClass->ClassId.UndiMajor, + sizeof (OptEnt.VendorClass->ClassId.UndiMajor) + ); + PxeBcUintnToAscDecWithFormat ( + Private->Nii->MinorVer, + OptEnt.VendorClass->ClassId.UndiMinor, + sizeof (OptEnt.VendorClass->ClassId.UndiMinor) + ); + } + + Index++; + + return Index; +} + + +/** + Cache the DHCPv6 packet. + + @param[in] Dst The pointer to the cache buffer for DHCPv6 pack= et. + @param[in] Src The pointer to the DHCPv6 packet to be cached. + +**/ +VOID +PxeBcCacheDhcp6Packet ( + IN EFI_DHCP6_PACKET *Dst, + IN EFI_DHCP6_PACKET *Src + ) +{ + ASSERT (Dst->Size >=3D Src->Length); + + CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length); + Dst->Length =3D Src->Length; +} + + +/** + Free all the nodes in the list for boot file. + + @param[in] Head The pointer to the head of list. + +**/ +VOID +PxeBcFreeBootFileOption ( + IN LIST_ENTRY *Head + ) +{ + LIST_ENTRY *Entry; + LIST_ENTRY *NextEntry; + PXEBC_DHCP6_OPTION_NODE *Node; + + NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, Head) { + Node =3D NET_LIST_USER_STRUCT (Entry, PXEBC_DHCP6_OPTION_NODE, Link); + RemoveEntryList (Entry); + FreePool (Node); + } +} + + +/** + Parse the Boot File URL option. + + @param[out] FileName The pointer to the boot file name. + @param[in, out] SrvAddr The pointer to the boot server address. + @param[in] BootFile The pointer to the boot file URL option dat= a. + @param[in] Length The length of the boot file URL option data= . + + @retval EFI_ABORTED User cancel operation. + @retval EFI_SUCCESS Selected the boot menu successfully. + @retval EFI_NOT_READY Read the input key from the keybroad has not fin= ish. + +**/ +EFI_STATUS +PxeBcExtractBootFileUrl ( + OUT UINT8 **FileName, + IN OUT EFI_IPv6_ADDRESS *SrvAddr, + IN CHAR8 *BootFile, + IN UINT16 Length + ) +{ + UINT16 PrefixLen; + CHAR8 *BootFileNamePtr; + CHAR8 *BootFileName; + UINT16 BootFileNameLen; + CHAR8 *TmpStr; + CHAR8 TmpChar; + CHAR8 *ServerAddressOption; + CHAR8 *ServerAddress; + CHAR8 *ModeStr; + EFI_STATUS Status; + + // + // The format of the Boot File URL option is: + // + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | OPT_BOOTFILE_URL | option-len | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | | + // . bootfile-url (variable length) . + // | | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // + + // + // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url= format + // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME + // As an example where the BOOTFILE_NAME is the EFI loader and + // SERVER_ADDRESS is the ASCII encoding of an IPV6 address. + // + PrefixLen =3D (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX); + + if (Length <=3D PrefixLen || + CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != =3D 0) { + return EFI_NOT_FOUND; + } + + BootFile =3D BootFile + PrefixLen; + Length =3D (UINT16) (Length - PrefixLen); + + TmpStr =3D (CHAR8 *) AllocateZeroPool (Length + 1); + if (TmpStr =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (TmpStr, BootFile, Length); + TmpStr[Length] =3D '\0'; + + // + // Get the part of SERVER_ADDRESS string. + // + ServerAddressOption =3D TmpStr; + if (*ServerAddressOption !=3D PXEBC_ADDR_START_DELIMITER) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + + ServerAddressOption ++; + ServerAddress =3D ServerAddressOption; + while (*ServerAddress !=3D '\0' && *ServerAddress !=3D PXEBC_ADDR_END_DE= LIMITER) { + ServerAddress++; + } + + if (*ServerAddress !=3D PXEBC_ADDR_END_DELIMITER) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + + *ServerAddress =3D '\0'; + + // + // Convert the string of server address to Ipv6 address format and store= it. + // + Status =3D NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); + if (EFI_ERROR (Status)) { + FreePool (TmpStr); + return Status; + } + + // + // Get the part of BOOTFILE_NAME string. + // + BootFileNamePtr =3D (CHAR8*)((UINTN)ServerAddress + 1); + if (*BootFileNamePtr !=3D PXEBC_TFTP_URL_SEPARATOR) { + FreePool (TmpStr); + return EFI_INVALID_PARAMETER; + } + + ++BootFileNamePtr; + BootFileNameLen =3D (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr -= (UINTN)TmpStr) + 1); + if (BootFileNameLen !=3D 0 || FileName !=3D NULL) { + // + // Remove trailing mode=3Doctet if present and ignore. All other mode= s are + // invalid for netboot6, so reject them. + // + ModeStr =3D AsciiStrStr (BootFileNamePtr, ";mode=3Doctet"); + if (ModeStr !=3D NULL && *(ModeStr + AsciiStrLen (";mode=3Doctet")) = =3D=3D '\0') { + *ModeStr =3D '\0'; + } else if (AsciiStrStr (BootFileNamePtr, ";mode=3D") !=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Extract boot file name from URL. + // + BootFileName =3D (CHAR8 *) AllocateZeroPool (BootFileNameLen); + if (BootFileName =3D=3D NULL) { + FreePool (TmpStr); + return EFI_OUT_OF_RESOURCES; + } + *FileName =3D (UINT8*) BootFileName; + + // + // Decode percent-encoding in boot file name. + // + while (*BootFileNamePtr !=3D '\0') { + if (*BootFileNamePtr =3D=3D '%') { + TmpChar =3D *(BootFileNamePtr+ 3); + *(BootFileNamePtr+ 3) =3D '\0'; + *BootFileName =3D (UINT8) AsciiStrHexToUintn ((CHAR8*)(BootFileNam= ePtr + 1)); + BootFileName++; + *(BootFileNamePtr+ 3) =3D TmpChar; + BootFileNamePtr +=3D 3; + } else { + *BootFileName =3D *BootFileNamePtr; + BootFileName++; + BootFileNamePtr++; + } + } + *BootFileName =3D '\0'; + } + + FreePool (TmpStr); + + return EFI_SUCCESS; +} + + +/** + Parse the Boot File Parameter option. + + @param[in] BootFilePara The pointer to boot file parameter option = data. + @param[out] BootFileSize The pointer to the parsed boot file size. + + @retval EFI_SUCCESS Successfully obtained the boot file size from pa= rameter option. + @retval EFI_NOT_FOUND Failed to extract the boot file size from parame= ter option. + +**/ +EFI_STATUS +PxeBcExtractBootFileParam ( + IN CHAR8 *BootFilePara, + OUT UINT16 *BootFileSize + ) +{ + UINT16 Length; + UINT8 Index; + UINT8 Digit; + UINT32 Size; + + CopyMem (&Length, BootFilePara, sizeof (UINT16)); + Length =3D NTOHS (Length); + + // + // The BootFile Size should be 1~5 byte ASCII strings + // + if (Length < 1 || Length > 5) { + return EFI_NOT_FOUND; + } + + // + // Extract the value of BootFile Size. + // + BootFilePara =3D BootFilePara + sizeof (UINT16); + Size =3D 0; + for (Index =3D 0; Index < Length; Index++) { + if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit, *(BootFilePara + Index)))) = { + return EFI_NOT_FOUND; + } + + Size =3D (Size + Digit) * 10; + } + + Size =3D Size / 10; + if (Size > PXEBC_DHCP6_MAX_BOOT_FILE_SIZE) { + return EFI_NOT_FOUND; + } + + *BootFileSize =3D (UINT16) Size; + return EFI_SUCCESS; +} + + +/** + Parse the cached DHCPv6 packet, including all the options. + + @param[in] Cache6 The pointer to a cached DHCPv6 packet. + + @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully. + @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet. + +**/ +EFI_STATUS +PxeBcParseDhcp6Packet ( + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 + ) +{ + EFI_DHCP6_PACKET *Offer; + EFI_DHCP6_PACKET_OPTION **Options; + EFI_DHCP6_PACKET_OPTION *Option; + PXEBC_OFFER_TYPE OfferType; + BOOLEAN IsProxyOffer; + BOOLEAN IsPxeOffer; + UINT32 Offset; + UINT32 Length; + UINT32 EnterpriseNum; + + IsProxyOffer =3D TRUE; + IsPxeOffer =3D FALSE; + Offer =3D &Cache6->Packet.Offer; + Options =3D Cache6->OptList; + + ZeroMem (Cache6->OptList, sizeof (Cache6->OptList)); + + Option =3D (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option); + Offset =3D 0; + Length =3D GET_DHCP6_OPTION_SIZE (Offer); + + // + // OpLen and OpCode here are both stored in network order, since they ar= e from original packet. + // + while (Offset < Length) { + + if (NTOHS (Option->OpCode) =3D=3D PXEBC_DHCP6_OPT_IA_NA) { + Options[PXEBC_DHCP6_IDX_IA_NA] =3D Option; + } else if (NTOHS (Option->OpCode) =3D=3D PXEBC_DHCP6_OPT_BOOT_FILE_URL= ) { + // + // The server sends this option to inform the client about an URL to= a boot file. + // + Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] =3D Option; + } else if (NTOHS (Option->OpCode) =3D=3D PXEBC_DHCP6_OPT_BOOT_FILE_PAR= AM) { + Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] =3D Option; + } else if (NTOHS (Option->OpCode) =3D=3D PXEBC_DHCP6_OPT_VENDOR_CLASS)= { + Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] =3D Option; + } + + Offset +=3D (NTOHS (Option->OpLen) + 4); + Option =3D (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset)= ; + } + + // + // The offer with assigned client address is NOT a proxy offer. + // An ia_na option, embeded with valid ia_addr option and a status_code = of success. + // + Option =3D Options[PXEBC_DHCP6_IDX_IA_NA]; + if (Option !=3D NULL) { + Option =3D PxeBcParseDhcp6Options ( + Option->Data + 12, + NTOHS (Option->OpLen), + PXEBC_DHCP6_OPT_STATUS_CODE + ); + if ((Option !=3D NULL && Option->Data[0] =3D=3D 0) || (Option =3D=3D N= ULL)) { + IsProxyOffer =3D FALSE; + } + } + + // + // The offer with "PXEClient" is a pxe offer. + // + Option =3D Options[PXEBC_DHCP6_IDX_VENDOR_CLASS]; + EnterpriseNum =3D HTONL(PXEBC_DHCP6_ENTERPRISE_NUM); + + if (Option !=3D NULL && + NTOHS(Option->OpLen) >=3D 13 && + CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) =3D=3D 0 = && + CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) =3D=3D 0) { + IsPxeOffer =3D TRUE; + } + + // + // Determine offer type of the dhcp6 packet. + // + if (IsPxeOffer) { + // + // It's a binl offer only with PXEClient. + // + OfferType =3D IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpB= inl; + } else { + // + // It's a dhcp only offer, which is a pure dhcp6 offer packet. + // + OfferType =3D PxeOfferTypeDhcpOnly; + } + + Cache6->OfferType =3D OfferType; + + return EFI_SUCCESS; +} + + +/** + Cache the DHCPv6 ack packet, and parse it on demand. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Ack The pointer to the DHCPv6 ack packet. + @param[in] Verified If TRUE, parse the ACK packet and store = info into mode data. + +**/ +VOID +PxeBcCopyDhcp6Ack ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP6_PACKET *Ack, + IN BOOLEAN Verified + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + + Mode =3D Private->PxeBc.Mode; + + PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack); + + if (Verified) { + // + // Parse the ack packet and store it into mode data if needed. + // + PxeBcParseDhcp6Packet (&Private->DhcpAck.Dhcp6); + CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length); + Mode->DhcpAckReceived =3D TRUE; + } +} + + +/** + Cache the DHCPv6 proxy offer packet according to the received order. + + @param[in] Private The pointer to PxeBc private data. + @param[in] OfferIndex The received order of offer packets. + +**/ +VOID +PxeBcCopyDhcp6Proxy ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 OfferIndex + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_DHCP6_PACKET *Offer; + + ASSERT (OfferIndex < Private->OfferNum); + ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM); + + Mode =3D Private->PxeBc.Mode; + Offer =3D &Private->OfferBuffer[OfferIndex].Dhcp6.Packet.Offer; + + // + // Cache the proxy offer packet and parse it. + // + PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer); + PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6); + + // + // Store this packet into mode data. + // + CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length); + Mode->ProxyOfferReceived =3D TRUE; +} + +/** + Seek the address of the first byte of the option header. + + @param[in] Buf The pointer to the buffer. + @param[in] SeekLen The length to seek. + @param[in] OptType The option type. + + @retval NULL If it failed to seek the option. + @retval others The position to the option. + +**/ +UINT8 * +PxeBcDhcp6SeekOption ( + IN UINT8 *Buf, + IN UINT32 SeekLen, + IN UINT16 OptType + ) +{ + UINT8 *Cursor; + UINT8 *Option; + UINT16 DataLen; + UINT16 OpCode; + + Option =3D NULL; + Cursor =3D Buf; + + while (Cursor < Buf + SeekLen) { + OpCode =3D ReadUnaligned16 ((UINT16 *) Cursor); + if (OpCode =3D=3D HTONS (OptType)) { + Option =3D Cursor; + break; + } + DataLen =3D NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2))); + Cursor +=3D (DataLen + 4); + } + + return Option; +} + + +/** + Build and send out the request packet for the bootfile, and parse the re= ply. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Index PxeBc option boot item type. + + @retval EFI_SUCCESS Successfully discovered the boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover the boot file. + +**/ +EFI_STATUS +PxeBcRequestBootService ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 Index + ) +{ + EFI_PXE_BASE_CODE_UDP_PORT SrcPort; + EFI_PXE_BASE_CODE_UDP_PORT DestPort; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; + UINTN DiscoverLen; + EFI_DHCP6_PACKET *Request; + UINTN RequestLen; + EFI_DHCP6_PACKET *Reply; + UINT8 *RequestOpt; + UINT8 *DiscoverOpt; + UINTN ReadSize; + UINT16 OpFlags; + UINT16 OpCode; + UINT16 OpLen; + EFI_STATUS Status; + EFI_DHCP6_PACKET *ProxyOffer; + UINT8 *Option; + + PxeBc =3D &Private->PxeBc; + Request =3D Private->Dhcp6Request; + ProxyOffer =3D &Private->OfferBuffer[Index].Dhcp6.Packet.Offer; + SrcPort =3D PXEBC_BS_DISCOVER_PORT; + DestPort =3D PXEBC_BS_DISCOVER_PORT; + OpFlags =3D 0; + + if (Request =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + Discover =3D AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET))= ; + if (Discover =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Build the request packet by the cached request packet before. + // + Discover->TransactionId =3D ProxyOffer->Dhcp6.Header.TransactionId; + Discover->MessageType =3D Request->Dhcp6.Header.MessageType; + RequestOpt =3D Request->Dhcp6.Option; + DiscoverOpt =3D Discover->DhcpOptions; + DiscoverLen =3D sizeof (EFI_DHCP6_HEADER); + RequestLen =3D DiscoverLen; + + // + // Find Server ID Option from ProxyOffer. + // + Option =3D PxeBcDhcp6SeekOption ( + ProxyOffer->Dhcp6.Option, + ProxyOffer->Length - 4, + PXEBC_DHCP6_OPT_SERVER_ID + ); + if (Option =3D=3D NULL) { + return EFI_NOT_FOUND; + } + =20 + // + // Add Server ID Option. + // + OpLen =3D NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen); + CopyMem (DiscoverOpt, Option, OpLen + 4); + DiscoverOpt +=3D (OpLen + 4); + DiscoverLen +=3D (OpLen + 4); + + while (RequestLen < Request->Length) { + OpCode =3D NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode); + OpLen =3D NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); + if (OpCode !=3D EFI_DHCP6_IA_TYPE_NA && + OpCode !=3D EFI_DHCP6_IA_TYPE_TA && + OpCode !=3D PXEBC_DHCP6_OPT_SERVER_ID + ) { + // + // Copy all the options except IA option and Server ID + // + CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); + DiscoverOpt +=3D (OpLen + 4); + DiscoverLen +=3D (OpLen + 4); + } + RequestOpt +=3D (OpLen + 4); + RequestLen +=3D (OpLen + 4); + } + + // + // Update Elapsed option in the package=20 + // + Option =3D PxeBcDhcp6SeekOption ( + Discover->DhcpOptions, + (UINT32)(RequestLen - 4), + PXEBC_DHCP6_OPT_ELAPSED_TIME + ); + if (Option !=3D NULL) { + CalcElapsedTime (Private); + WriteUnaligned16 ((UINT16*)(Option + 4), HTONS((UINT16) Private->Elaps= edTime)); + } =20 + + Status =3D PxeBc->UdpWrite ( + PxeBc, + OpFlags, + &Private->ServerIp, + &DestPort, + NULL, + &Private->StationIp, + &SrcPort, + NULL, + NULL, + &DiscoverLen, + (VOID *) Discover + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Cache the right PXE reply packet here, set valid flag later. + // Especially for PXE discover packet, store it into mode data here. + // + Reply =3D &Private->ProxyOffer.Dhcp6.Packet.Offer; + ReadSize =3D (UINTN) Reply->Size; + + // + // Start Udp6Read instance + // + Status =3D Private->Udp6Read->Configure (Private->Udp6Read, &Private->Ud= p6CfgData); + if (EFI_ERROR (Status)) { + return Status; + } + =20 + Status =3D PxeBc->UdpRead ( + PxeBc, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BAS= E_CODE_UDP_OPFLAGS_ANY_DEST_IP, + NULL, + &SrcPort, + &Private->ServerIp, + &DestPort, + NULL, + NULL, + &ReadSize, + (VOID *) &Reply->Dhcp6 + ); + // + // Stop Udp6Read instance + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Update length + // + Reply->Length =3D (UINT32) ReadSize; + + return EFI_SUCCESS; +} + + +/** + Retry to request bootfile name by the BINL offer. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Index The received order of offer packets. + + @retval EFI_SUCCESS Successfully retried a request for the = bootfile name. + @retval EFI_DEVICE_ERROR Failed to retry the bootfile name. + +**/ +EFI_STATUS +PxeBcRetryDhcp6Binl ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 Index + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + PXEBC_DHCP6_PACKET_CACHE *Offer; + PXEBC_DHCP6_PACKET_CACHE *Cache6; + EFI_STATUS Status; + + ASSERT (Index < PXEBC_OFFER_MAX_NUM); + ASSERT (Private->OfferBuffer[Index].Dhcp6.OfferType =3D=3D PxeOfferTypeD= hcpBinl || + Private->OfferBuffer[Index].Dhcp6.OfferType =3D=3D PxeOfferTypeP= roxyBinl); + + Mode =3D Private->PxeBc.Mode; + Private->IsDoDiscover =3D FALSE; + Offer =3D &Private->OfferBuffer[Index].Dhcp6; + if (Offer->OfferType =3D=3D PxeOfferTypeDhcpBinl) { + // + // There is no BootFileUrl option in dhcp6 offer, so use servers multi= -cast address instead. + // + CopyMem ( + &Private->ServerIp.v6, + &mAllDhcpRelayAndServersAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + } else { + ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] !=3D NULL); + // + // Parse out the next server address from the last offer, and store it + // + Status =3D PxeBcExtractBootFileUrl ( + &Private->BootFileName, + &Private->ServerIp.v6, + (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->D= ata), + NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen= ) + ); + if (EFI_ERROR (Status)) { + return Status; + } + } + + // + // Retry Dhcp6Binl again for the bootfile, and the reply cached into Pri= vate->ProxyOffer. + // + Status =3D PxeBcRequestBootService (Private, Index); + + if (EFI_ERROR (Status)) { + return Status; + } + + Cache6 =3D &Private->ProxyOffer.Dhcp6; + Status =3D PxeBcParseDhcp6Packet (Cache6); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Cache6->OfferType !=3D PxeOfferTypeProxyPxe10 && + Cache6->OfferType !=3D PxeOfferTypeProxyWfm11a && + Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] =3D=3D NULL) { + // + // This BINL ack doesn't have discovery option set or multicast option= set + // or bootfile name specified. + // + return EFI_DEVICE_ERROR; + } + + Mode->ProxyOfferReceived =3D TRUE; + CopyMem ( + &Mode->ProxyOffer.Dhcpv6, + &Cache6->Packet.Offer.Dhcp6, + Cache6->Packet.Offer.Length + ); + + return EFI_SUCCESS; +} + + +/** + Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + @param[in] RcvdOffer The pointer to the received offer pack= et. + +**/ +VOID +PxeBcCacheDhcp6Offer ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP6_PACKET *RcvdOffer + ) +{ + PXEBC_DHCP6_PACKET_CACHE *Cache6; + EFI_DHCP6_PACKET *Offer; + PXEBC_OFFER_TYPE OfferType; + + Cache6 =3D &Private->OfferBuffer[Private->OfferNum].Dhcp6; + Offer =3D &Cache6->Packet.Offer; + + // + // Cache the content of DHCPv6 packet firstly. + // + PxeBcCacheDhcp6Packet (Offer, RcvdOffer); + + // + // Validate the DHCPv6 packet, and parse the options and offer type. + // + if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) { + return ; + } + + // + // Determine whether cache the current offer by type, and record OfferIn= dex and OfferCount. + // + OfferType =3D Cache6->OfferType; + ASSERT (OfferType < PxeOfferTypeMax); + ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM); + + if (IS_PROXY_OFFER (OfferType)) { + // + // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL = offer. + // + Private->IsProxyRecved =3D TRUE; + + if (OfferType =3D=3D PxeOfferTypeProxyBinl) { + // + // Cache all proxy BINL offers. + // + Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] =3D P= rivate->OfferNum; + Private->OfferCount[OfferType]++; + } else if (Private->OfferCount[OfferType] > 0) { + // + // Only cache the first PXE10/WFM11a offer, and discard the others. + // + Private->OfferIndex[OfferType][0] =3D Private->OfferNum; + Private->OfferCount[OfferType] =3D 1; + } else { + return; + } + } else { + // + // It's a DHCPv6 offer with yiaddr, and cache them all. + // + Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] =3D Pri= vate->OfferNum; + Private->OfferCount[OfferType]++; + } + + Private->OfferNum++; +} + + +/** + Select an DHCPv6 offer, and record SelectIndex and SelectProxyType. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + +**/ +VOID +PxeBcSelectDhcp6Offer ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + UINT32 Index; + UINT32 OfferIndex; + PXEBC_OFFER_TYPE OfferType; + + Private->SelectIndex =3D 0; + + if (Private->IsOfferSorted) { + // + // Select offer by default policy. + // + if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) { + // + // 1. DhcpPxe10 offer + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpPxe10][= 0] + 1; + + } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) { + // + // 2. DhcpWfm11a offer + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpWfm11a]= [0] + 1; + + } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && + Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) { + // + // 3. DhcpOnly offer and ProxyPxe10 offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnl= y][0] + 1; + Private->SelectProxyType =3D PxeOfferTypeProxyPxe10; + + } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && + Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) { + // + // 4. DhcpOnly offer and ProxyWfm11a offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnl= y][0] + 1; + Private->SelectProxyType =3D PxeOfferTypeProxyWfm11a; + + } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) { + // + // 5. DhcpBinl offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpBinl][0= ] + 1; + + } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 && + Private->OfferCount[PxeOfferTypeProxyBinl] > 0) { + // + // 6. DhcpOnly offer and ProxyBinl offer. + // + Private->SelectIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnl= y][0] + 1; + Private->SelectProxyType =3D PxeOfferTypeProxyBinl; + + } else { + // + // 7. DhcpOnly offer with bootfilename. + // + for (Index =3D 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly];= Index++) { + OfferIndex =3D Private->OfferIndex[PxeOfferTypeDhcpOnly][Index]; + if (Private->OfferBuffer[OfferIndex].Dhcp6.OptList[PXEBC_DHCP6_IDX= _BOOT_FILE_URL] !=3D NULL) { + Private->SelectIndex =3D OfferIndex + 1; + break; + } + } + } + } else { + // + // Select offer by received order. + // + for (Index =3D 0; Index < Private->OfferNum; Index++) { + + OfferType =3D Private->OfferBuffer[Index].Dhcp6.OfferType; + + if (IS_PROXY_OFFER (OfferType)) { + // + // Skip proxy offers + // + continue; + } + + if (!Private->IsProxyRecved && + OfferType =3D=3D PxeOfferTypeDhcpOnly && + Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_F= ILE_URL] =3D=3D NULL) { + // + // Skip if DhcpOnly offer without any other proxy offers or bootfi= lename. + // + continue; + } + + Private->SelectIndex =3D Index + 1; + break; + } + } +} + + +/** + Handle the DHCPv6 offer packet. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS Handled the DHCPv6 offer packet successf= ully. + @retval EFI_NO_RESPONSE No response to the following request pac= ket. + +**/ +EFI_STATUS +PxeBcHandleDhcp6Offer ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + PXEBC_DHCP6_PACKET_CACHE *Cache6; + EFI_STATUS Status; + PXEBC_OFFER_TYPE OfferType; + UINT32 ProxyIndex; + UINT32 SelectIndex; + UINT32 Index; + + ASSERT (Private->SelectIndex > 0); + SelectIndex =3D (UINT32) (Private->SelectIndex - 1); + ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); + Cache6 =3D &Private->OfferBuffer[SelectIndex].Dhcp6; + Status =3D EFI_SUCCESS; + + if (Cache6->OfferType =3D=3D PxeOfferTypeDhcpBinl) { + // + // DhcpBinl offer is selected, so need try to request bootfilename by = this offer. + // + if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) { + Status =3D EFI_NO_RESPONSE; + } + } else if (Cache6->OfferType =3D=3D PxeOfferTypeDhcpOnly) { + + if (Private->IsProxyRecved) { + // + // DhcpOnly offer is selected, so need try to request bootfilename. + // + ProxyIndex =3D 0; + if (Private->IsOfferSorted) { + // + // The proxy offer should be determined if select by default polic= y. + // IsOfferSorted means all offers are labeled by OfferIndex. + // + ASSERT (Private->OfferCount[Private->SelectProxyType] > 0); + + if (Private->SelectProxyType =3D=3D PxeOfferTypeProxyBinl) { + // + // Try all the cached ProxyBinl offer one by one to request boot= filename. + // + for (Index =3D 0; Index < Private->OfferCount[Private->SelectPro= xyType]; Index++) { + + ProxyIndex =3D Private->OfferIndex[Private->SelectProxyType][I= ndex]; + if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) { + break; + } + } + if (Index =3D=3D Private->OfferCount[Private->SelectProxyType]) = { + Status =3D EFI_NO_RESPONSE; + } + } else { + // + // For other proxy offers (pxe10 or wfm11a), only one is buffere= d. + // + ProxyIndex =3D Private->OfferIndex[Private->SelectProxyType][0]; + } + } else { + // + // The proxy offer should not be determined if select by received = order. + // + Status =3D EFI_NO_RESPONSE; + + for (Index =3D 0; Index < Private->OfferNum; Index++) { + + OfferType =3D Private->OfferBuffer[Index].Dhcp6.OfferType; + + if (!IS_PROXY_OFFER (OfferType)) { + // + // Skip non proxy dhcp offers. + // + continue; + } + + if (OfferType =3D=3D PxeOfferTypeProxyBinl) { + // + // Try all the cached ProxyBinl offer one by one to request bo= otfilename. + // + if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, Index))) { + continue; + } + } + + Private->SelectProxyType =3D OfferType; + ProxyIndex =3D Index; + Status =3D EFI_SUCCESS; + break; + } + } + + if (!EFI_ERROR (Status) && Private->SelectProxyType !=3D PxeOfferTyp= eProxyBinl) { + // + // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer,= copy and parse it. + // + PxeBcCopyDhcp6Proxy (Private, ProxyIndex); + } + } else { + // + // Othewise, the bootfilename must be included in DhcpOnly offer. + // + ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] !=3D NULL); + } + } + + if (!EFI_ERROR (Status)) { + // + // All PXE boot information is ready by now. + // + PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE); + Private->PxeBc.Mode->DhcpDiscoverValid =3D TRUE; + } + + return Status; +} + + +/** + Unregister the address by Ip6Config protocol. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + +**/ +VOID +PxeBcUnregisterIp6Address ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + if (Private->Ip6Policy !=3D PXEBC_IP6_POLICY_MAX) { + // + // PXE driver change the policy of IP6 driver, it's a chance to recove= r. + // Keep the point and there is no enough requirements to do recovery. + // + } +} + +/** + Check whether IP driver could route the message which will be sent to Se= rverIp address. + =20 + This function will check the IP6 route table every 1 seconds until speci= fied timeout is expired, if a valid + route is found in IP6 route table, the address will be filed in GatewayA= ddr and return. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + @param[in] TimeOutInSecond Timeout value in seconds. + @param[out] GatewayAddr Pointer to store the gateway IP address. + + @retval EFI_SUCCESS Found a valid gateway address successful= ly. + @retval EFI_TIMEOUT The operation is time out. + @retval Other Unexpect error happened. + =20 +**/ +EFI_STATUS +PxeBcCheckRouteTable ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINTN TimeOutInSecond, + OUT EFI_IPv6_ADDRESS *GatewayAddr + ) +{ + EFI_STATUS Status; + EFI_IP6_PROTOCOL *Ip6; + EFI_IP6_MODE_DATA Ip6ModeData; + UINTN Index; + EFI_EVENT TimeOutEvt; + UINTN RetryCount; + BOOLEAN GatewayIsFound; + + ASSERT (GatewayAddr !=3D NULL); + ASSERT (Private !=3D NULL); + + Ip6 =3D Private->Ip6; + GatewayIsFound =3D FALSE; + RetryCount =3D 0; + TimeOutEvt =3D NULL; + ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS)); + + while (TRUE) { + Status =3D Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Find out the gateway address which can route the message which send= to ServerIp. + // + for (Index =3D 0; Index < Ip6ModeData.RouteCount; Index++) { + if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable= [Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) { + IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gate= way); + GatewayIsFound =3D TRUE; + break; + } + } + + if (Ip6ModeData.AddressList !=3D NULL) { + FreePool (Ip6ModeData.AddressList); + } + if (Ip6ModeData.GroupTable !=3D NULL) { + FreePool (Ip6ModeData.GroupTable); + } + if (Ip6ModeData.RouteTable !=3D NULL) { + FreePool (Ip6ModeData.RouteTable); + } + if (Ip6ModeData.NeighborCache !=3D NULL) { + FreePool (Ip6ModeData.NeighborCache); + } + if (Ip6ModeData.PrefixTable !=3D NULL) { + FreePool (Ip6ModeData.PrefixTable); + } + if (Ip6ModeData.IcmpTypeList !=3D NULL) { + FreePool (Ip6ModeData.IcmpTypeList); + } + =20 + if (GatewayIsFound || RetryCount =3D=3D TimeOutInSecond) { + break; + } + =20 + RetryCount++; + =20 + // + // Delay 1 second then recheck it again. + // + if (TimeOutEvt =3D=3D NULL) { + Status =3D gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &TimeOutEvt + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + + Status =3D gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND)= ; + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { + Ip6->Poll (Ip6); + } + } + =20 +ON_EXIT: + if (TimeOutEvt !=3D NULL) { + gBS->CloseEvent (TimeOutEvt); + } + =20 + if (GatewayIsFound) { + Status =3D EFI_SUCCESS; + } else if (RetryCount =3D=3D TimeOutInSecond) { + Status =3D EFI_TIMEOUT; + } + + return Status;=20 +} + +/** + Register the ready station address and gateway by Ip6Config protocol. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + @param[in] Address The pointer to the ready address. + + @retval EFI_SUCCESS Registered the address succesfully. + @retval Others Failed to register the address. + +**/ +EFI_STATUS +PxeBcRegisterIp6Address ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_IPv6_ADDRESS *Address + ) +{ + EFI_IP6_PROTOCOL *Ip6; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_IP6_CONFIG_POLICY Policy; + EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr; + EFI_IPv6_ADDRESS GatewayAddr; + UINTN DataSize; + EFI_EVENT MappedEvt; + EFI_STATUS Status; + BOOLEAN NoGateway; + EFI_IPv6_ADDRESS *Ip6Addr; + UINTN Index; + + Status =3D EFI_SUCCESS; + MappedEvt =3D NULL; + Ip6Addr =3D NULL; + DataSize =3D sizeof (EFI_IP6_CONFIG_POLICY); + Ip6Cfg =3D Private->Ip6Cfg; + Ip6 =3D Private->Ip6; + NoGateway =3D FALSE; + + ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); + CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS)); + + Status =3D Ip6->Configure (Ip6, &Private->Ip6CfgData); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Retrieve the gateway address from IP6 route table. + // + Status =3D PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT,= &GatewayAddr); + if (EFI_ERROR (Status)) { + NoGateway =3D TRUE; + } + =20 + // + // There is no channel between IP6 and PXE driver about address setting, + // so it has to set the new address by Ip6ConfigProtocol manually. + // + Policy =3D Ip6ConfigPolicyManual; + Status =3D Ip6Cfg->SetData ( + Ip6Cfg, + Ip6ConfigDataTypePolicy, + sizeof(EFI_IP6_CONFIG_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + // + // There is no need to recover later. + // + Private->Ip6Policy =3D PXEBC_IP6_POLICY_MAX; + goto ON_EXIT; + } + + // + // Create a notify event to set address flag when DAD if IP6 driver succ= eeded. + // + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &Private->IsAddressOk, + &MappedEvt + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Private->IsAddressOk =3D FALSE; + Status =3D Ip6Cfg->RegisterDataNotify ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + if (EFI_ERROR(Status)) { + goto ON_EXIT; + } + + Status =3D Ip6Cfg->SetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS), + &CfgAddr + ); + if (EFI_ERROR(Status) && Status !=3D EFI_NOT_READY) { + goto ON_EXIT; + } else if (Status =3D=3D EFI_NOT_READY) { + // + // Poll the network until the asynchronous process is finished. + // + while (!Private->IsAddressOk) { + Ip6->Poll (Ip6); + } + // + // Check whether the IP6 address setting is successed. + // + DataSize =3D 0; + Status =3D Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + NULL + ); + if (Status !=3D EFI_BUFFER_TOO_SMALL || DataSize =3D=3D 0) { + Status =3D EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + Ip6Addr =3D AllocatePool (DataSize); + if (Ip6Addr =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status =3D Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + (VOID*) Ip6Addr + ); + if (EFI_ERROR (Status)) { + Status =3D EFI_DEVICE_ERROR; + goto ON_EXIT; + } + + for (Index =3D 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index+= +) { + if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS))= =3D=3D 0) { + break; + } + } + if (Index =3D=3D DataSize / sizeof (EFI_IPv6_ADDRESS)) { + Status =3D EFI_ABORTED; + goto ON_EXIT; + } + } + =20 + // + // Set the default gateway address back if needed. + // + if (!NoGateway && !NetIp6IsUnspecifiedAddr (&GatewayAddr)) { + Status =3D Ip6Cfg->SetData ( + Ip6Cfg, + Ip6ConfigDataTypeGateway, + sizeof (EFI_IPv6_ADDRESS), + &GatewayAddr + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } + +ON_EXIT: + if (MappedEvt !=3D NULL) { + Ip6Cfg->UnregisterDataNotify ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + MappedEvt + ); + gBS->CloseEvent (MappedEvt); + } + if (Ip6Addr !=3D NULL) { + FreePool (Ip6Addr); + } + return Status; +} + +/** + Set the IP6 policy to Automatic. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS Switch the IP policy succesfully. + @retval Others Unexpect error happened. + +**/ +EFI_STATUS +PxeBcSetIp6Policy ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + EFI_IP6_CONFIG_POLICY Policy; + EFI_STATUS Status; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + UINTN DataSize; + + Ip6Cfg =3D Private->Ip6Cfg; + DataSize =3D sizeof (EFI_IP6_CONFIG_POLICY); + + // + // Get and store the current policy of IP6 driver. + // + Status =3D Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypePolicy, + &DataSize, + &Private->Ip6Policy + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Private->Ip6Policy =3D=3D Ip6ConfigPolicyManual) { + Policy =3D Ip6ConfigPolicyAutomatic; + Status =3D Ip6Cfg->SetData ( + Ip6Cfg, + Ip6ConfigDataTypePolicy, + sizeof(EFI_IP6_CONFIG_POLICY), + &Policy + ); + if (EFI_ERROR (Status)) { + // + // There is no need to recover later. + // + Private->Ip6Policy =3D PXEBC_IP6_POLICY_MAX; + } + } + + return Status; +} + +/** + This function will register the station IP address and flush IP instance= to start using the new IP address. + =20 + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS The new IP address has been configured s= uccessfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +PxeBcSetIp6Address ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_DHCP6_PROTOCOL *Dhcp6; + =20 + Dhcp6 =3D Private->Dhcp6; + + CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_= IPv6_ADDRESS)); + CopyMem (&Private->PxeBc.Mode->StationIp.v6, &Private->StationIp.v6, siz= eof (EFI_IPv6_ADDRESS)); + + Status =3D PxeBcRegisterIp6Address (Private, &Private->StationIp.v6); + if (EFI_ERROR (Status)) { + Dhcp6->Stop (Dhcp6); + return Status; + } + + Status =3D PxeBcFlushStationIp (Private, &Private->StationIp, NULL); + if (EFI_ERROR (Status)) { + PxeBcUnregisterIp6Address (Private); + Dhcp6->Stop (Dhcp6); + return Status; + } + + AsciiPrint ("\n Station IP address is "); + PxeBcShowIp6Addr (&Private->StationIp.v6); + + return EFI_SUCCESS; +} + +/** + EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protoco= l driver + to intercept events that occurred in the configuration process. + + @param[in] This The pointer to the EFI DHCPv6 Protocol. + @param[in] Context The pointer to the context set by EFI_DHCP= 6_PROTOCOL.Configure(). + @param[in] CurrentState The current operational state of the EFI D= HCPv Protocol driver. + @param[in] Dhcp6Event The event that occurs in the current state= , which usually means a + state transition. + @param[in] Packet The DHCPv6 packet that is going to be sent= or was already received. + @param[out] NewPacket The packet that is used to replace the Pac= ket above. + + @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to con= tinue the DHCP process. + @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The= EFI DHCPv6 Protocol + driver will continue to wait for more pack= ets. + @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abo= rt the current process. + +**/ +EFI_STATUS +EFIAPI +PxeBcDhcp6CallBack ( + IN EFI_DHCP6_PROTOCOL *This, + IN VOID *Context, + IN EFI_DHCP6_STATE CurrentState, + IN EFI_DHCP6_EVENT Dhcp6Event, + IN EFI_DHCP6_PACKET *Packet, + OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; + EFI_DHCP6_PACKET *SelectAd; + EFI_STATUS Status; + BOOLEAN Received; + + if ((Dhcp6Event !=3D Dhcp6RcvdAdvertise) && + (Dhcp6Event !=3D Dhcp6SelectAdvertise) && + (Dhcp6Event !=3D Dhcp6SendSolicit) && + (Dhcp6Event !=3D Dhcp6SendRequest) && + (Dhcp6Event !=3D Dhcp6RcvdReply)) { + return EFI_SUCCESS; + } + + ASSERT (Packet !=3D NULL); + + Private =3D (PXEBC_PRIVATE_DATA *) Context; + Mode =3D Private->PxeBc.Mode; + Callback =3D Private->PxeBcCallback; + + // + // Callback to user when any traffic ocurred if has. + // + if (Dhcp6Event !=3D Dhcp6SelectAdvertise && Callback !=3D NULL) { + Received =3D (BOOLEAN) (Dhcp6Event =3D=3D Dhcp6RcvdAdvertise || Dhcp6E= vent =3D=3D Dhcp6RcvdReply); + Status =3D Callback->Callback ( + Callback, + Private->Function, + Received, + Packet->Length, + (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp6 + ); + if (Status !=3D EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + return EFI_ABORTED; + } + } + + Status =3D EFI_SUCCESS; + + switch (Dhcp6Event) { + + case Dhcp6SendSolicit: + // + // Record the first Solicate msg time + // + if (Private->SolicitTimes =3D=3D 0) { + CalcElapsedTime (Private); + Private->SolicitTimes++; + } + // + // Cache the dhcp discover packet to mode data directly. + // + CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length); + break; + + case Dhcp6RcvdAdvertise: + Status =3D EFI_NOT_READY; + if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) { + // + // Cache the dhcp offers to OfferBuffer[] for select later, and reco= rd + // the OfferIndex and OfferCount. + // + PxeBcCacheDhcp6Offer (Private, Packet); + } + break; + + case Dhcp6SendRequest: + // + // Store the request packet as seed packet for discover. + // + if (Private->Dhcp6Request !=3D NULL) { + FreePool (Private->Dhcp6Request); + } + Private->Dhcp6Request =3D AllocateZeroPool (Packet->Size); + if (Private->Dhcp6Request !=3D NULL) { + CopyMem (Private->Dhcp6Request, Packet, Packet->Size); + } + break; + + case Dhcp6SelectAdvertise: + // + // Select offer by the default policy or by order, and record the Sele= ctIndex + // and SelectProxyType. + // + PxeBcSelectDhcp6Offer (Private); + + if (Private->SelectIndex =3D=3D 0) { + Status =3D EFI_ABORTED; + } else { + ASSERT (NewPacket !=3D NULL); + SelectAd =3D &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6= .Packet.Offer; + *NewPacket =3D AllocateZeroPool (SelectAd->Size); + ASSERT (*NewPacket !=3D NULL); + CopyMem (*NewPacket, SelectAd, SelectAd->Size); + } + break; + + case Dhcp6RcvdReply: + // + // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack= in mode data + // without verification. + // + ASSERT (Private->SelectIndex !=3D 0); + PxeBcCopyDhcp6Ack (Private, Packet, FALSE); + break; + + default: + ASSERT (0); + } + + return Status; +} + + +/** + Build and send out the request packet for the bootfile, and parse the re= ply. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Type PxeBc option boot item type. + @param[in] Layer The pointer to option boot item layer. + @param[in] UseBis Use BIS or not. + @param[in] DestIp The pointer to the server address. + + @retval EFI_SUCCESS Successfully discovered the boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover the boot file. + +**/ +EFI_STATUS +PxeBcDhcp6Discover ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_IP_ADDRESS *DestIp + ) +{ + EFI_PXE_BASE_CODE_UDP_PORT SrcPort; + EFI_PXE_BASE_CODE_UDP_PORT DestPort; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; + UINTN DiscoverLen; + EFI_DHCP6_PACKET *Request; + UINTN RequestLen; + EFI_DHCP6_PACKET *Reply; + UINT8 *RequestOpt; + UINT8 *DiscoverOpt; + UINTN ReadSize; + UINT16 OpCode; + UINT16 OpLen; + UINT32 Xid; + EFI_STATUS Status; + + PxeBc =3D &Private->PxeBc; + Mode =3D PxeBc->Mode; + Request =3D Private->Dhcp6Request; + SrcPort =3D PXEBC_BS_DISCOVER_PORT; + DestPort =3D PXEBC_BS_DISCOVER_PORT; + + if (!UseBis && Layer !=3D NULL) { + *Layer &=3D EFI_PXE_BASE_CODE_BOOT_LAYER_MASK; + } + + if (Request =3D=3D NULL) { + return EFI_DEVICE_ERROR; + } + + Discover =3D AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET))= ; + if (Discover =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Build the discover packet by the cached request packet before. + // + Xid =3D NET_RANDOM (NetRandomInitSeed ()); + Discover->TransactionId =3D HTONL (Xid); + Discover->MessageType =3D Request->Dhcp6.Header.MessageType; + RequestOpt =3D Request->Dhcp6.Option; + DiscoverOpt =3D Discover->DhcpOptions; + DiscoverLen =3D sizeof (EFI_DHCP6_HEADER); + RequestLen =3D DiscoverLen; + + while (RequestLen < Request->Length) { + OpCode =3D NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode); + OpLen =3D NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); + if (OpCode !=3D EFI_DHCP6_IA_TYPE_NA && + OpCode !=3D EFI_DHCP6_IA_TYPE_TA) { + // + // Copy all the options except IA option. + // + CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); + DiscoverOpt +=3D (OpLen + 4); + DiscoverLen +=3D (OpLen + 4); + } + RequestOpt +=3D (OpLen + 4); + RequestLen +=3D (OpLen + 4); + } + + Status =3D PxeBc->UdpWrite ( + PxeBc, + 0, + &Private->ServerIp, + &DestPort, + NULL, + &Private->StationIp, + &SrcPort, + NULL, + NULL, + &DiscoverLen, + (VOID *) Discover + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Cache the right PXE reply packet here, set valid flag later. + // Especially for PXE discover packet, store it into mode data here. + // + if (Private->IsDoDiscover) { + CopyMem (&Mode->PxeDiscover.Dhcpv6, Discover, DiscoverLen); + Reply =3D &Private->PxeReply.Dhcp6.Packet.Ack; + } else { + Reply =3D &Private->ProxyOffer.Dhcp6.Packet.Offer; + } + ReadSize =3D (UINTN) Reply->Size; + + // + // Start Udp6Read instance + // + Status =3D Private->Udp6Read->Configure (Private->Udp6Read, &Private->Ud= p6CfgData); + if (EFI_ERROR (Status)) { + return Status; + } + =20 + Status =3D PxeBc->UdpRead ( + PxeBc, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, + NULL, + &SrcPort, + &Private->ServerIp, + &DestPort, + NULL, + NULL, + &ReadSize, + (VOID *) &Reply->Dhcp6 + ); + // + // Stop Udp6Read instance + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + + +/** + Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other = PXE boot information. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL + + @retval EFI_SUCCESS The S.A.R.R. process successfully finished= . + @retval Others Failed to finish the S.A.R.R. process. + +**/ +EFI_STATUS +PxeBcDhcp6Sarr ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP6_PROTOCOL *Dhcp6 + ) +{ + EFI_PXE_BASE_CODE_MODE *PxeMode; + EFI_DHCP6_CONFIG_DATA Config; + EFI_DHCP6_MODE_DATA Mode; + EFI_DHCP6_RETRANSMISSION *Retransmit; + EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM]; + UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE]; + UINT32 OptCount; + EFI_STATUS Status; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_STATUS TimerStatus; + EFI_EVENT Timer; + UINT64 GetMappingTimeOut; + UINTN DataSize; + EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; + + Status =3D EFI_SUCCESS; + PxeMode =3D Private->PxeBc.Mode; + Ip6Cfg =3D Private->Ip6Cfg; + Timer =3D NULL; + + // + // Build option list for the request packet. + // + OptCount =3D PxeBcBuildDhcp6Options (Private, OptList, Buffer); + ASSERT (OptCount> 0); + + Retransmit =3D AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); + if (Retransmit =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA)); + ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA)); + + Config.OptionCount =3D OptCount; + Config.OptionList =3D OptList; + Config.Dhcp6Callback =3D PxeBcDhcp6CallBack; + Config.CallbackContext =3D Private; + Config.IaInfoEvent =3D NULL; + Config.RapidCommit =3D FALSE; + Config.ReconfigureAccept =3D FALSE; + Config.IaDescriptor.IaId =3D Private->IaId; + Config.IaDescriptor.Type =3D EFI_DHCP6_IA_TYPE_NA; + Config.SolicitRetransmission =3D Retransmit; + Retransmit->Irt =3D 4; + Retransmit->Mrc =3D 4; + Retransmit->Mrt =3D 32; + Retransmit->Mrd =3D 60; + + // + // Configure the DHCPv6 instance for PXE boot. + // + Status =3D Dhcp6->Configure (Dhcp6, &Config); + FreePool (Retransmit); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Initialize the record fields for DHCPv6 offer in private data. + // + Private->IsProxyRecved =3D FALSE; + Private->OfferNum =3D 0; + Private->SelectIndex =3D 0; + ZeroMem (Private->OfferCount, sizeof (Private->OfferCount)); + ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex)); + + + // + // Start DHCPv6 S.A.R.R. process to acquire IPv6 address. + // + Status =3D Dhcp6->Start (Dhcp6); + if (Status =3D=3D EFI_NO_MAPPING) { + // + // IP6 Linklocal address is not available for use, so stop current Dhc= p process + // and wait for duplicate address detection to finish. + // + Dhcp6->Stop (Dhcp6); + + // + // Get Duplicate Address Detection Transmits count. + // + DataSize =3D sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); + Status =3D Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + &DataSize, + &DadXmits + ); + if (EFI_ERROR (Status)) { + Dhcp6->Configure (Dhcp6, NULL); + return Status; + } + + Status =3D gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Tim= er); + if (EFI_ERROR (Status)) { + Dhcp6->Configure (Dhcp6, NULL); + return Status; + } + + GetMappingTimeOut =3D TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmi= ts + PXEBC_DAD_ADDITIONAL_DELAY; + Status =3D gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (Timer); + Dhcp6->Configure (Dhcp6, NULL); + return Status; + } + + do { + =20 + TimerStatus =3D gBS->CheckEvent (Timer); + if (!EFI_ERROR (TimerStatus)) { + Status =3D Dhcp6->Start (Dhcp6); + } + } while (TimerStatus =3D=3D EFI_NOT_READY); + =20 + gBS->CloseEvent (Timer); + } + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_ICMP_ERROR) { + PxeMode->IcmpErrorReceived =3D TRUE; + } + Dhcp6->Configure (Dhcp6, NULL); + return Status; + } + + // + // Get the acquired IPv6 address and store them. + // + Status =3D Dhcp6->GetModeData (Dhcp6, &Mode, NULL); + if (EFI_ERROR (Status)) { + Dhcp6->Stop (Dhcp6); + return Status; + } + + ASSERT (Mode.Ia->State =3D=3D Dhcp6Bound); + // + // DHCP6 doesn't have an option to specify the router address on the sub= net, the only way to get the + // router address in IP6 is the router discovery mechanism (the RS and R= A, which only be handled when + // the IP policy is Automatic). So we just hold the station IP address h= ere and leave the IP policy as + // Automatic, until we get the server IP address. This could let IP6 dri= ver finish the router discovery=20 + // to find a valid router address. + // + CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, si= zeof (EFI_IPv6_ADDRESS)); + + // + // Check the selected offer whether BINL retry is needed. + // + Status =3D PxeBcHandleDhcp6Offer (Private); + if (EFI_ERROR (Status)) { + Dhcp6->Stop (Dhcp6); + return Status; + } + =20 + return EFI_SUCCESS; +} diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcDhcp6.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/Networ= kPkg/UefiPxeBcDxe/PxeBcDhcp6.h new file mode 100644 index 0000000..3ebf552 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcDhcp6.h @@ -0,0 +1,303 @@ +/** @file + Functions declaration related with DHCPv6 for UefiPxeBc Driver. + + Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __EFI_PXEBC_DHCP6_H__ +#define __EFI_PXEBC_DHCP6_H__ + +#define PXEBC_DHCP6_OPTION_MAX_NUM 16 +#define PXEBC_DHCP6_OPTION_MAX_SIZE 312 +#define PXEBC_DHCP6_PACKET_MAX_SIZE 1472 +#define PXEBC_IP6_POLICY_MAX 0xff +#define PXEBC_IP6_ROUTE_TABLE_TIMEOUT 10 + +#define PXEBC_DHCP6_S_PORT 547 +#define PXEBC_DHCP6_C_PORT 546 + +#define PXEBC_DHCP6_OPT_CLIENT_ID 1 +#define PXEBC_DHCP6_OPT_SERVER_ID 2 +#define PXEBC_DHCP6_OPT_IA_NA 3 +#define PXEBC_DHCP6_OPT_IA_TA 4 +#define PXEBC_DHCP6_OPT_IAADDR 5 +#define PXEBC_DHCP6_OPT_ORO 6 +#define PXEBC_DHCP6_OPT_PREFERENCE 7 +#define PXEBC_DHCP6_OPT_ELAPSED_TIME 8 +#define PXEBC_DHCP6_OPT_REPLAY_MSG 9 +#define PXEBC_DHCP6_OPT_AUTH 11 +#define PXEBC_DHCP6_OPT_UNICAST 12 +#define PXEBC_DHCP6_OPT_STATUS_CODE 13 +#define PXEBC_DHCP6_OPT_RAPID_COMMIT 14 +#define PXEBC_DHCP6_OPT_USER_CLASS 15 +#define PXEBC_DHCP6_OPT_VENDOR_CLASS 16 +#define PXEBC_DHCP6_OPT_VENDOR_OPTS 17 +#define PXEBC_DHCP6_OPT_INTERFACE_ID 18 +#define PXEBC_DHCP6_OPT_RECONFIG_MSG 19 +#define PXEBC_DHCP6_OPT_RECONFIG_ACCEPT 20 +#define PXEBC_DHCP6_OPT_BOOT_FILE_URL 59 // Assigned by IANA, RFC 5= 970 +#define PXEBC_DHCP6_OPT_BOOT_FILE_PARAM 60 // Assigned by IANA, RFC 5= 970 +#define PXEBC_DHCP6_OPT_ARCH 61 // Assigned by IANA, RFC 5= 970 +#define PXEBC_DHCP6_OPT_UNDI 62 // Assigned by IANA, RFC 5= 970 +#define PXEBC_DHCP6_ENTERPRISE_NUM 343 // TODO: IANA TBD: tempora= rily using Intel's +#define PXEBC_DHCP6_MAX_BOOT_FILE_SIZE 65535 // It's a limitation of = bit length, 65535*512 bytes. + + +#define PXEBC_DHCP6_IDX_IA_NA 0 +#define PXEBC_DHCP6_IDX_BOOT_FILE_URL 1 +#define PXEBC_DHCP6_IDX_BOOT_FILE_PARAM 2 +#define PXEBC_DHCP6_IDX_VENDOR_CLASS 3 +#define PXEBC_DHCP6_IDX_MAX 4 + +#define PXEBC_DHCP6_BOOT_FILE_URL_PREFIX "tftp://" +#define PXEBC_TFTP_URL_SEPARATOR '/' +#define PXEBC_ADDR_START_DELIMITER '[' +#define PXEBC_ADDR_END_DELIMITER ']' + +#define GET_NEXT_DHCP6_OPTION(Opt) \ + (EFI_DHCP6_PACKET_OPTION *) ((UINT8 *) (Opt) + \ + sizeof (EFI_DHCP6_PACKET_OPTION) + (NTOHS ((Opt)->OpLen)) - 1) + +#define GET_DHCP6_OPTION_SIZE(Pkt) \ + ((Pkt)->Length - sizeof (EFI_DHCP6_HEADER)) + +#define IS_PROXY_OFFER(Type) \ + ((Type) =3D=3D PxeOfferTypeProxyBinl || \ + (Type) =3D=3D PxeOfferTypeProxyPxe10 || \ + (Type) =3D=3D PxeOfferTypeProxyWfm11a) + + +#pragma pack(1) +typedef struct { + UINT16 OpCode[256]; +} PXEBC_DHCP6_OPTION_ORO; + +typedef struct { + UINT8 Type; + UINT8 MajorVer; + UINT8 MinorVer; +} PXEBC_DHCP6_OPTION_UNDI; + +typedef struct { + UINT16 Type; +} PXEBC_DHCP6_OPTION_ARCH; + +typedef struct { + UINT8 ClassIdentifier[10]; + UINT8 ArchitecturePrefix[5]; + UINT8 ArchitectureType[5]; + UINT8 Lit3[1]; + UINT8 InterfaceName[4]; + UINT8 Lit4[1]; + UINT8 UndiMajor[3]; + UINT8 UndiMinor[3]; +} PXEBC_CLASS_ID; + +typedef struct { + UINT32 Vendor; + UINT16 ClassLen; + PXEBC_CLASS_ID ClassId; +} PXEBC_DHCP6_OPTION_VENDOR_CLASS; + +#pragma pack() + +typedef union { + PXEBC_DHCP6_OPTION_ORO *Oro; + PXEBC_DHCP6_OPTION_UNDI *Undi; + PXEBC_DHCP6_OPTION_ARCH *Arch; + PXEBC_DHCP6_OPTION_VENDOR_CLASS *VendorClass; +} PXEBC_DHCP6_OPTION_ENTRY; + +typedef struct { + LIST_ENTRY Link; + EFI_DHCP6_PACKET_OPTION *Option; + UINT8 Precedence; +} PXEBC_DHCP6_OPTION_NODE; + +typedef union { + EFI_DHCP6_PACKET Offer; + EFI_DHCP6_PACKET Ack; + UINT8 Buffer[PXEBC_DHCP6_PACKET_MAX_SIZE]; +} PXEBC_DHCP6_PACKET; + +typedef struct { + PXEBC_DHCP6_PACKET Packet; + PXEBC_OFFER_TYPE OfferType; + EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_IDX_MAX]; +} PXEBC_DHCP6_PACKET_CACHE; + + +/** + Free all the nodes in the boot file list. + + @param[in] Head The pointer to the head of the list. + +**/ +VOID +PxeBcFreeBootFileOption ( + IN LIST_ENTRY *Head + ); + + +/** + Parse the Boot File URL option. + + @param[out] FileName The pointer to the boot file name. + @param[in, out] SrvAddr The pointer to the boot server address. + @param[in] BootFile The pointer to the boot file URL option dat= a. + @param[in] Length Length of the boot file URL option data. + + @retval EFI_ABORTED User canceled the operation. + @retval EFI_SUCCESS Selected the boot menu successfully. + @retval EFI_NOT_READY Read the input key from the keybroad has not fin= ish. + +**/ +EFI_STATUS +PxeBcExtractBootFileUrl ( + OUT UINT8 **FileName, + IN OUT EFI_IPv6_ADDRESS *SrvAddr, + IN CHAR8 *BootFile, + IN UINT16 Length + ); + + +/** + Parse the Boot File Parameter option. + + @param[in] BootFilePara The pointer to the boot file parameter opt= ion data. + @param[out] BootFileSize The pointer to the parsed boot file size. + + @retval EFI_SUCCESS Successfully obtained the boot file size from pa= rameter option. + @retval EFI_NOT_FOUND Failed to extract the boot file size from parame= ter option. + +**/ +EFI_STATUS +PxeBcExtractBootFileParam ( + IN CHAR8 *BootFilePara, + OUT UINT16 *BootFileSize + ); + + +/** + Parse the cached DHCPv6 packet, including all the options. + + @param[in] Cache6 The pointer to a cached DHCPv6 packet. + + @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully. + @retval EFI_DEVICE_ERROR Failed to parse and invalid packet. + +**/ +EFI_STATUS +PxeBcParseDhcp6Packet ( + IN PXEBC_DHCP6_PACKET_CACHE *Cache6 + ); + + +/** + Register the ready address by Ip6Config protocol. + + @param[in] Private The pointer to the PxeBc private data. + @param[in] Address The pointer to the ready address. + + @retval EFI_SUCCESS Registered the address succesfully. + @retval Others Failed to register the address. + +**/ +EFI_STATUS +PxeBcRegisterIp6Address ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_IPv6_ADDRESS *Address + ); + + +/** + Unregister the address by Ip6Config protocol. + + @param[in] Private The pointer to the PxeBc private data. + +**/ +VOID +PxeBcUnregisterIp6Address ( + IN PXEBC_PRIVATE_DATA *Private + ); + + +/** + Build and send out the request packet for the bootfile, and parse the re= ply. + + @param[in] Private The pointer to the PxeBc private data. + @param[in] Type PxeBc option boot item type. + @param[in] Layer The pointer to the option boot item la= yer. + @param[in] UseBis Use BIS or not. + @param[in] DestIp The pointer to the server address. + + @retval EFI_SUCCESS Successfully discovered theboot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resource. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover boot file. + +**/ +EFI_STATUS +PxeBcDhcp6Discover ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT16 Type, + IN UINT16 *Layer, + IN BOOLEAN UseBis, + IN EFI_IP_ADDRESS *DestIp + ); + +/** + Set the IP6 policy to Automatic. + + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS Switch the IP policy succesfully. + @retval Others Unexpect error happened. + +**/ +EFI_STATUS +PxeBcSetIp6Policy ( + IN PXEBC_PRIVATE_DATA *Private + ); + +/** + This function will register the station IP address and flush IP instance= to start using the new IP address. + =20 + @param[in] Private The pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS The new IP address has been configured s= uccessfully. + @retval Others Failed to configure the address. + +**/ +EFI_STATUS +PxeBcSetIp6Address ( + IN PXEBC_PRIVATE_DATA *Private + ); + +/** + Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other = PXE boot information. + + @param[in] Private The pointer to the PxeBc private data. + @param[in] Dhcp6 The pointer to EFI_DHCP6_PROTOCOL. + + @retval EFI_SUCCESS The S.A.R.R. process successfully finished= . + @retval Others Failed to finish the S.A.R.R. process. + +**/ +EFI_STATUS +PxeBcDhcp6Sarr ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_DHCP6_PROTOCOL *Dhcp6 + ); + +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcDriver.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Netwo= rkPkg/UefiPxeBcDxe/PxeBcDriver.c new file mode 100644 index 0000000..de8d59c --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcDriver.c @@ -0,0 +1,1825 @@ +/** @file + Driver Binding functions implementationfor for UefiPxeBc Driver. + + (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + + +EFI_DRIVER_BINDING_PROTOCOL gPxeBcIp4DriverBinding =3D { + PxeBcIp4DriverBindingSupported, + PxeBcIp4DriverBindingStart, + PxeBcIp4DriverBindingStop, + 0xa, + NULL, + NULL +}; + +EFI_DRIVER_BINDING_PROTOCOL gPxeBcIp6DriverBinding =3D { + PxeBcIp6DriverBindingSupported, + PxeBcIp6DriverBindingStart, + PxeBcIp6DriverBindingStop, + 0xa, + NULL, + NULL +}; + +/** + Get the Nic handle using any child handle in the IPv4 stack. + + @param[in] ControllerHandle Pointer to child handle over IPv4. + + @return NicHandle The pointer to the Nic handle. + +**/ +EFI_HANDLE +PxeBcGetNicByIp4Children ( + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_HANDLE NicHandle; + + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiArpProtocolGuid= ); + if (NicHandle =3D=3D NULL) { + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiIp4ProtocolGu= id); + if (NicHandle =3D=3D NULL) { + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiUdp4Protoco= lGuid); + if (NicHandle =3D=3D NULL) { + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiDhcp4Prot= ocolGuid); + if (NicHandle =3D=3D NULL) { + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiMtftp4P= rotocolGuid); + if (NicHandle =3D=3D NULL) { + return NULL; + } + } + } + } + } + + return NicHandle; +} + + +/** + Get the Nic handle using any child handle in the IPv6 stack. + + @param[in] ControllerHandle Pointer to child handle over IPv6. + + @return NicHandle The pointer to the Nic handle. + +**/ +EFI_HANDLE +PxeBcGetNicByIp6Children ( + IN EFI_HANDLE ControllerHandle + ) +{ + EFI_HANDLE NicHandle; + + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiIp6ProtocolGuid= ); + if (NicHandle =3D=3D NULL) { + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiUdp6ProtocolG= uid); + if (NicHandle =3D=3D NULL) { + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiDhcp6Protoc= olGuid); + if (NicHandle =3D=3D NULL) { + NicHandle =3D NetLibGetNicHandle (ControllerHandle, &gEfiMtftp6Pro= tocolGuid); + if (NicHandle =3D=3D NULL) { + return NULL; + } + } + } + } + + return NicHandle; +} + + +/** + Destroy the opened instances based on IPv4. + + @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL= . + @param[in] Private Pointer to PXEBC_PRIVATE_DATA. + +**/ +VOID +PxeBcDestroyIp4Children ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN PXEBC_PRIVATE_DATA *Private + ) +{ + ASSERT(Private !=3D NULL); + + if (Private->ArpChild !=3D NULL) { + // + // Close Arp for PxeBc->Arp and destroy the instance. + // + gBS->CloseProtocol ( + Private->ArpChild, + &gEfiArpProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiArpServiceBindingProtocolGuid, + Private->ArpChild + ); + } + + if (Private->Ip4Child !=3D NULL) { + // + // Close Ip4 for background ICMP error message and destroy the instanc= e. + // + gBS->CloseProtocol ( + Private->Ip4Child, + &gEfiIp4ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiIp4ServiceBindingProtocolGuid, + Private->Ip4Child + ); + } + + if (Private->Udp4WriteChild !=3D NULL) { + // + // Close Udp4 for PxeBc->UdpWrite and destroy the instance. + // + gBS->CloseProtocol ( + Private->Udp4WriteChild, + &gEfiUdp4ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + Private->Udp4WriteChild + ); + } + + if (Private->Udp4ReadChild !=3D NULL) { + // + // Close Udp4 for PxeBc->UdpRead and destroy the instance. + // + gBS->CloseProtocol ( + Private->Udp4ReadChild, + &gEfiUdp4ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + Private->Udp4ReadChild + ); + } + + if (Private->Mtftp4Child !=3D NULL) { + // + // Close Mtftp4 for PxeBc->Mtftp4 and destroy the instance. + // + gBS->CloseProtocol ( + Private->Mtftp4Child, + &gEfiMtftp4ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + Private->Mtftp4Child + ); + } + + if (Private->Dhcp4Child !=3D NULL) { + // + // Close Dhcp4 for PxeBc->Dhcp4 and destroy the instance. + // + gBS->CloseProtocol ( + Private->Dhcp4Child, + &gEfiDhcp4ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiDhcp4ServiceBindingProtocolGuid, + Private->Dhcp4Child + ); + } + + if (Private->Ip4Nic !=3D NULL) { + // + // Close PxeBcPrivate from the parent Nic handle and destroy the virtu= al handle. + // + gBS->CloseProtocol ( + Private->Controller, + &gEfiCallerIdGuid, + This->DriverBindingHandle, + Private->Ip4Nic->Controller + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Private->Ip4Nic->Controller, + &gEfiDevicePathProtocolGuid, + Private->Ip4Nic->DevicePath, + &gEfiLoadFileProtocolGuid, + &Private->Ip4Nic->LoadFile, + &gEfiPxeBaseCodeProtocolGuid, + &Private->PxeBc, + NULL + ); + + if (Private->Snp !=3D NULL) {=20 + // + // Close SNP from the child virtual handle + // + gBS->CloseProtocol ( + Private->Ip4Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + This->DriverBindingHandle, + Private->Ip4Nic->Controller + ); + =20 + gBS->UninstallProtocolInterface ( + Private->Ip4Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + Private->Snp + ); + } + FreePool (Private->Ip4Nic); + } + + Private->ArpChild =3D NULL; + Private->Ip4Child =3D NULL; + Private->Udp4WriteChild =3D NULL; + Private->Udp4ReadChild =3D NULL; + Private->Mtftp4Child =3D NULL; + Private->Dhcp4Child =3D NULL; + Private->Ip4Nic =3D NULL; +} + + +/** + Destroy the opened instances based on IPv6. + + @param[in] This Pointer to the EFI_DRIVER_BINDING_PROTOCOL= . + @param[in] Private Pointer to PXEBC_PRIVATE_DATA. + +**/ +VOID +PxeBcDestroyIp6Children ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN PXEBC_PRIVATE_DATA *Private + ) +{ + ASSERT(Private !=3D NULL); + + if (Private->Ip6Child !=3D NULL) { + // + // Close Ip6 for Ip6->Ip6Config and destroy the instance. + // + gBS->CloseProtocol ( + Private->Ip6Child, + &gEfiIp6ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiIp6ServiceBindingProtocolGuid, + Private->Ip6Child + ); + } + + if (Private->Udp6WriteChild !=3D NULL) { + // + // Close Udp6 for PxeBc->UdpWrite and destroy the instance. + // + gBS->CloseProtocol ( + Private->Udp6WriteChild, + &gEfiUdp6ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + Private->Udp6WriteChild + ); + } + + if (Private->Udp6ReadChild !=3D NULL) { + // + // Close Udp6 for PxeBc->UdpRead and destroy the instance. + // + gBS->CloseProtocol ( + Private->Udp6ReadChild, + &gEfiUdp6ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + Private->Udp6ReadChild + ); + } + + if (Private->Mtftp6Child !=3D NULL) { + // + // Close Mtftp6 for PxeBc->Mtftp and destroy the instance. + // + gBS->CloseProtocol ( + Private->Mtftp6Child, + &gEfiMtftp6ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiMtftp6ServiceBindingProtocolGuid, + Private->Mtftp6Child + ); + } + + if (Private->Dhcp6Child !=3D NULL) { + // + // Close Dhcp6 for PxeBc->Dhcp and destroy the instance. + // + gBS->CloseProtocol ( + Private->Dhcp6Child, + &gEfiDhcp6ProtocolGuid, + This->DriverBindingHandle, + Private->Controller + ); + + NetLibDestroyServiceChild ( + Private->Controller, + This->DriverBindingHandle, + &gEfiDhcp6ServiceBindingProtocolGuid, + Private->Dhcp6Child + ); + } + + if (Private->Ip6Nic !=3D NULL) { + // + // Close PxeBcPrivate from the parent Nic handle and destroy the virtu= al handle. + // + gBS->CloseProtocol ( + Private->Controller, + &gEfiCallerIdGuid, + This->DriverBindingHandle, + Private->Ip6Nic->Controller + ); + + gBS->UninstallMultipleProtocolInterfaces ( + Private->Ip6Nic->Controller, + &gEfiDevicePathProtocolGuid, + Private->Ip6Nic->DevicePath, + &gEfiLoadFileProtocolGuid, + &Private->Ip6Nic->LoadFile, + &gEfiPxeBaseCodeProtocolGuid, + &Private->PxeBc, + NULL + ); + if (Private->Snp !=3D NULL) { + // + // Close SNP from the child virtual handle + // + gBS->CloseProtocol ( + Private->Ip6Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + This->DriverBindingHandle, + Private->Ip6Nic->Controller + ); + gBS->UninstallProtocolInterface ( + Private->Ip6Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + Private->Snp + ); + } + FreePool (Private->Ip6Nic); + } + + Private->Ip6Child =3D NULL; + Private->Udp6WriteChild =3D NULL; + Private->Udp6ReadChild =3D NULL; + Private->Mtftp6Child =3D NULL; + Private->Dhcp6Child =3D NULL; + Private->Ip6Nic =3D NULL; + Private->Mode.Ipv6Available =3D FALSE; +} + +/** + Check whether UNDI protocol supports IPv6. + + @param[in] ControllerHandle Controller handle. + @param[in] Private Pointer to PXEBC_PRIVATE_DATA. + @param[out] Ipv6Support TRUE if UNDI supports IPv6. + + @retval EFI_SUCCESS Get the result whether UNDI supports IPv6= by NII or AIP protocol successfully. + @retval EFI_NOT_FOUND Don't know whether UNDI supports IPv6 sin= ce NII or AIP is not available. + +**/ +EFI_STATUS +PxeBcCheckIpv6Support ( + IN EFI_HANDLE ControllerHandle, + IN PXEBC_PRIVATE_DATA *Private, + OUT BOOLEAN *Ipv6Support + ) +{ + EFI_HANDLE Handle; + EFI_ADAPTER_INFORMATION_PROTOCOL *Aip; + EFI_STATUS Status; + EFI_GUID *InfoTypesBuffer; + UINTN InfoTypeBufferCount; + UINTN TypeIndex; + BOOLEAN Supported; + VOID *InfoBlock; + UINTN InfoBlockSize; + + ASSERT (Private !=3D NULL && Ipv6Support !=3D NULL); + + // + // Check whether the UNDI supports IPv6 by NII protocol. + // + if (Private->Nii !=3D NULL) { + *Ipv6Support =3D Private->Nii->Ipv6Supported; + return EFI_SUCCESS; + } + + // + // Check whether the UNDI supports IPv6 by AIP protocol. + // + + // + // Get the NIC handle by SNP protocol. + // =20 + Handle =3D NetLibGetSnpHandle (ControllerHandle, NULL); + if (Handle =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + Aip =3D NULL; + Status =3D gBS->HandleProtocol ( + Handle, + &gEfiAdapterInformationProtocolGuid, + (VOID *) &Aip + ); + if (EFI_ERROR (Status) || Aip =3D=3D NULL) { + return EFI_NOT_FOUND; + } + + InfoTypesBuffer =3D NULL; + InfoTypeBufferCount =3D 0; + Status =3D Aip->GetSupportedTypes (Aip, &InfoTypesBuffer, &InfoTypeBuffe= rCount); + if (EFI_ERROR (Status) || InfoTypesBuffer =3D=3D NULL) { + FreePool (InfoTypesBuffer); + return EFI_NOT_FOUND; + } + + Supported =3D FALSE; + for (TypeIndex =3D 0; TypeIndex < InfoTypeBufferCount; TypeIndex++) { + if (CompareGuid (&InfoTypesBuffer[TypeIndex], &gEfiAdapterInfoUndiIpv6= SupportGuid)) { + Supported =3D TRUE; + break; + } + } + + FreePool (InfoTypesBuffer); + if (!Supported) { + return EFI_NOT_FOUND; + } + + // + // We now have adapter information block. + // + InfoBlock =3D NULL; + InfoBlockSize =3D 0; + Status =3D Aip->GetInformation (Aip, &gEfiAdapterInfoUndiIpv6SupportGuid= , &InfoBlock, &InfoBlockSize); + if (EFI_ERROR (Status) || InfoBlock =3D=3D NULL) { + FreePool (InfoBlock); + return EFI_NOT_FOUND; + } =20 + + *Ipv6Support =3D ((EFI_ADAPTER_INFO_UNDI_IPV6_SUPPORT *) InfoBlock)->Ipv= 6Support; + FreePool (InfoBlock); + return EFI_SUCCESS; + +} + +/** + Create the opened instances based on IPv4. + + @param[in] This Pointer to EFI_DRIVER_BINDING_PROTOCOL. + @param[in] ControllerHandle Handle of the child to destroy. + @param[in] Private Handle Pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS The instances based on IPv4 were all creat= ed successfully. + @retval Others An unexpected error occurred. + +**/ +EFI_STATUS +PxeBcCreateIp4Children ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN PXEBC_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + IPv4_DEVICE_PATH Ip4Node; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_UDP4_CONFIG_DATA *Udp4CfgData; + EFI_IP4_CONFIG_DATA *Ip4CfgData; + EFI_IP4_MODE_DATA Ip4ModeData; + PXEBC_PRIVATE_PROTOCOL *Id; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + + if (Private->Ip4Nic !=3D NULL) { + // + // Already created before. + // + return EFI_SUCCESS; + } + + // + // Create Dhcp4 child and open Dhcp4 protocol for PxeBc->Dhcp. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiDhcp4ServiceBindingProtocolGuid, + &Private->Dhcp4Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Dhcp4Child, + &gEfiDhcp4ProtocolGuid, + (VOID **) &Private->Dhcp4, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Mtftp4 child and open Mtftp4 protocol for PxeBc->Mtftp. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiMtftp4ServiceBindingProtocolGuid, + &Private->Mtftp4Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Mtftp4Child, + &gEfiMtftp4ProtocolGuid, + (VOID **) &Private->Mtftp4, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Udp4 child and open Udp4 protocol for PxeBc->UdpRead. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + &Private->Udp4ReadChild + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Udp4ReadChild, + &gEfiUdp4ProtocolGuid, + (VOID **) &Private->Udp4Read, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Udp4 child and open Udp4 protocol for PxeBc->UdpWrite. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiUdp4ServiceBindingProtocolGuid, + &Private->Udp4WriteChild + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Udp4WriteChild, + &gEfiUdp4ProtocolGuid, + (VOID **) &Private->Udp4Write, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Arp child and open Arp protocol for PxeBc->Arp. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiArpServiceBindingProtocolGuid, + &Private->ArpChild + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->ArpChild, + &gEfiArpProtocolGuid, + (VOID **) &Private->Arp, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Ip4 child and open Ip4 protocol for background ICMP packets. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiIp4ServiceBindingProtocolGuid, + &Private->Ip4Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Ip4Child, + &gEfiIp4ProtocolGuid, + (VOID **) &Private->Ip4, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Get max packet size from Ip4 to calculate block size for Tftp later. + // + Status =3D Private->Ip4->GetModeData (Private->Ip4, &Ip4ModeData, NULL, = NULL); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Private->Ip4MaxPacketSize =3D Ip4ModeData.MaxPacketSize; + + Private->Ip4Nic =3D AllocateZeroPool (sizeof (PXEBC_VIRTUAL_NIC)); + if (Private->Ip4Nic =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->Ip4Nic->Private =3D Private; + Private->Ip4Nic->Signature =3D PXEBC_VIRTUAL_NIC_SIGNATURE; + + // + // Locate Ip4->Ip4Config2 and store it for set IPv4 Policy. + // + Status =3D gBS->HandleProtocol ( + ControllerHandle, + &gEfiIp4Config2ProtocolGuid, + (VOID **) &Private->Ip4Config2 + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create a device path node for Ipv4 virtual nic, and append it. + // + ZeroMem (&Ip4Node, sizeof (IPv4_DEVICE_PATH)); + Ip4Node.Header.Type =3D MESSAGING_DEVICE_PATH; + Ip4Node.Header.SubType =3D MSG_IPv4_DP; + Ip4Node.StaticIpAddress =3D FALSE; + + SetDevicePathNodeLength (&Ip4Node.Header, sizeof (Ip4Node)); + + Private->Ip4Nic->DevicePath =3D AppendDevicePathNode (Private->DevicePat= h, &Ip4Node.Header); + + if (Private->Ip4Nic->DevicePath =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + CopyMem ( + &Private->Ip4Nic->LoadFile, + &gLoadFileProtocolTemplate, + sizeof (EFI_LOAD_FILE_PROTOCOL) + ); + + // + // Create a new handle for IPv4 virtual nic, + // and install PxeBaseCode, LoadFile and DevicePath protocols. + // + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &Private->Ip4Nic->Controller, + &gEfiDevicePathProtocolGuid, + Private->Ip4Nic->DevicePath, + &gEfiLoadFileProtocolGuid, + &Private->Ip4Nic->LoadFile, + &gEfiPxeBaseCodeProtocolGuid, + &Private->PxeBc, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + if (Private->Snp !=3D NULL) { + // + // Install SNP protocol on purpose is for some OS loader backward + // compatibility consideration. + // + Status =3D gBS->InstallProtocolInterface ( + &Private->Ip4Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + EFI_NATIVE_INTERFACE, + Private->Snp + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Open SNP on the child handle BY_DRIVER. It will prevent any additio= nally=20 + // layering to perform the experiment. + // + Status =3D gBS->OpenProtocol ( + Private->Ip4Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &Snp, + This->DriverBindingHandle, + Private->Ip4Nic->Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + // + // Open PxeBaseCodePrivate protocol by child to setup a parent-child rel= ationship between + // real NIC handle and the virtual IPv4 NIC handle. + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + Private->Ip4Nic->Controller, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Set default configure data for Udp4Read and Ip4 instance. + // + Mode =3D Private->PxeBc.Mode; + Udp4CfgData =3D &Private->Udp4CfgData; + Ip4CfgData =3D &Private->Ip4CfgData; + + Udp4CfgData->AcceptBroadcast =3D FALSE; + Udp4CfgData->AcceptAnyPort =3D TRUE; + Udp4CfgData->AllowDuplicatePort =3D TRUE; + Udp4CfgData->TypeOfService =3D Mode->ToS; + Udp4CfgData->TimeToLive =3D Mode->TTL; + Udp4CfgData->ReceiveTimeout =3D PXEBC_DEFAULT_LIFETIME; + Udp4CfgData->TransmitTimeout =3D PXEBC_DEFAULT_LIFETIME; + + Ip4CfgData->AcceptIcmpErrors =3D TRUE; + Ip4CfgData->DefaultProtocol =3D EFI_IP_PROTO_ICMP; + Ip4CfgData->TypeOfService =3D Mode->ToS; + Ip4CfgData->TimeToLive =3D Mode->TTL; + Ip4CfgData->ReceiveTimeout =3D PXEBC_DEFAULT_LIFETIME; + Ip4CfgData->TransmitTimeout =3D PXEBC_DEFAULT_LIFETIME; + + return EFI_SUCCESS; + +ON_ERROR: + PxeBcDestroyIp4Children (This, Private); + return Status; +} + + +/** + Create the opened instances based on IPv6. + + @param[in] This Pointer to EFI_DRIVER_BINDING_PROTOCOL. + @param[in] ControllerHandle Handle of the child to destroy. + @param[in] Private Handle Pointer to PXEBC_PRIVATE_DATA. + + @retval EFI_SUCCESS The instances based on IPv6 were all creat= ed successfully. + @retval Others An unexpected error occurred. + +**/ +EFI_STATUS +PxeBcCreateIp6Children ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN PXEBC_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + IPv6_DEVICE_PATH Ip6Node; + EFI_UDP6_CONFIG_DATA *Udp6CfgData; + EFI_IP6_CONFIG_DATA *Ip6CfgData; + EFI_IP6_MODE_DATA Ip6ModeData; + PXEBC_PRIVATE_PROTOCOL *Id; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp; + UINTN Index; + + if (Private->Ip6Nic !=3D NULL) { + // + // Already created before. + // + return EFI_SUCCESS; + } + + Private->Ip6Nic =3D AllocateZeroPool (sizeof (PXEBC_VIRTUAL_NIC)); + + if (Private->Ip6Nic =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->Ip6Nic->Private =3D Private; + Private->Ip6Nic->Signature =3D PXEBC_VIRTUAL_NIC_SIGNATURE; + + // + // Create Dhcp6 child and open Dhcp6 protocol for PxeBc->Dhcp. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiDhcp6ServiceBindingProtocolGuid, + &Private->Dhcp6Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Dhcp6Child, + &gEfiDhcp6ProtocolGuid, + (VOID **) &Private->Dhcp6, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Generate a random IAID for the Dhcp6 assigned address. + // + Private->IaId =3D NET_RANDOM (NetRandomInitSeed ()); + if (Private->Snp !=3D NULL) { + for (Index =3D 0; Index < Private->Snp->Mode->HwAddressSize; Index++) = { + Private->IaId |=3D (Private->Snp->Mode->CurrentAddress.Addr[Index] <= < ((Index << 3) & 31)); + } =20 + } + + // + // Create Mtftp6 child and open Mtftp6 protocol for PxeBc->Mtftp. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiMtftp6ServiceBindingProtocolGuid, + &Private->Mtftp6Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Mtftp6Child, + &gEfiMtftp6ProtocolGuid, + (VOID **) &Private->Mtftp6, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Udp6 child and open Udp6 protocol for PxeBc->UdpRead. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + &Private->Udp6ReadChild + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Udp6ReadChild, + &gEfiUdp6ProtocolGuid, + (VOID **) &Private->Udp6Read, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Udp6 child and open Udp6 protocol for PxeBc->UdpWrite. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiUdp6ServiceBindingProtocolGuid, + &Private->Udp6WriteChild + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Udp6WriteChild, + &gEfiUdp6ProtocolGuid, + (VOID **) &Private->Udp6Write, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create Ip6 child and open Ip6 protocol for background ICMP6 packets. + // + Status =3D NetLibCreateServiceChild ( + ControllerHandle, + This->DriverBindingHandle, + &gEfiIp6ServiceBindingProtocolGuid, + &Private->Ip6Child + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Status =3D gBS->OpenProtocol ( + Private->Ip6Child, + &gEfiIp6ProtocolGuid, + (VOID **) &Private->Ip6, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Get max packet size from Ip6 to calculate block size for Tftp later. + // + Status =3D Private->Ip6->GetModeData (Private->Ip6, &Ip6ModeData, NULL, = NULL); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Private->Ip6MaxPacketSize =3D Ip6ModeData.MaxPacketSize; + + // + // Locate Ip6->Ip6Config and store it for set IPv6 address. + // + Status =3D gBS->HandleProtocol ( + ControllerHandle, + &gEfiIp6ConfigProtocolGuid, + (VOID **) &Private->Ip6Cfg + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create a device path node for Ipv6 virtual nic, and append it. + // + ZeroMem (&Ip6Node, sizeof (IPv6_DEVICE_PATH)); + Ip6Node.Header.Type =3D MESSAGING_DEVICE_PATH; + Ip6Node.Header.SubType =3D MSG_IPv6_DP; + Ip6Node.PrefixLength =3D IP6_PREFIX_LENGTH; + + SetDevicePathNodeLength (&Ip6Node.Header, sizeof (Ip6Node)); + + Private->Ip6Nic->DevicePath =3D AppendDevicePathNode (Private->DevicePat= h, &Ip6Node.Header); + + if (Private->Ip6Nic->DevicePath =3D=3D NULL) { + Status =3D EFI_OUT_OF_RESOURCES; + goto ON_ERROR; + } + + CopyMem ( + &Private->Ip6Nic->LoadFile, + &gLoadFileProtocolTemplate, + sizeof (EFI_LOAD_FILE_PROTOCOL) + ); + + // + // Create a new handle for IPv6 virtual nic, + // and install PxeBaseCode, LoadFile and DevicePath protocols. + // + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &Private->Ip6Nic->Controller, + &gEfiDevicePathProtocolGuid, + Private->Ip6Nic->DevicePath, + &gEfiLoadFileProtocolGuid, + &Private->Ip6Nic->LoadFile, + &gEfiPxeBaseCodeProtocolGuid, + &Private->PxeBc, + NULL + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + =20 + if (Private->Snp !=3D NULL) { + // + // Install SNP protocol on purpose is for some OS loader backward + // compatibility consideration. + // + Status =3D gBS->InstallProtocolInterface ( + &Private->Ip6Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + EFI_NATIVE_INTERFACE, + Private->Snp + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Open SNP on the child handle BY_DRIVER. It will prevent any additio= nally=20 + // layering to perform the experiment. + // + Status =3D gBS->OpenProtocol ( + Private->Ip6Nic->Controller, + &gEfiSimpleNetworkProtocolGuid, + (VOID **) &Snp, + This->DriverBindingHandle, + Private->Ip6Nic->Controller, + EFI_OPEN_PROTOCOL_BY_DRIVER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + // + // Open PxeBaseCodePrivate protocol by child to setup a parent-child rel= ationship between + // real NIC handle and the virtual IPv6 NIC handle. + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + Private->Ip6Nic->Controller, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Set IPv6 avaiable flag and set default configure data for + // Udp6Read and Ip6 instance. + // + Status =3D PxeBcCheckIpv6Support (ControllerHandle, Private, &Private->M= ode.Ipv6Available); + if (EFI_ERROR (Status)) { + // + // Fail to get the data whether UNDI supports IPv6. Set default value. + // + Private->Mode.Ipv6Available =3D TRUE; + } + + if (!Private->Mode.Ipv6Available) { + goto ON_ERROR; + } + + Udp6CfgData =3D &Private->Udp6CfgData; + Ip6CfgData =3D &Private->Ip6CfgData; + + Udp6CfgData->AcceptAnyPort =3D TRUE; + Udp6CfgData->AllowDuplicatePort =3D TRUE; + Udp6CfgData->HopLimit =3D PXEBC_DEFAULT_HOPLIMIT; + Udp6CfgData->ReceiveTimeout =3D PXEBC_DEFAULT_LIFETIME; + Udp6CfgData->TransmitTimeout =3D PXEBC_DEFAULT_LIFETIME; + + Ip6CfgData->AcceptIcmpErrors =3D TRUE; + Ip6CfgData->DefaultProtocol =3D IP6_ICMP; + Ip6CfgData->HopLimit =3D PXEBC_DEFAULT_HOPLIMIT; + Ip6CfgData->ReceiveTimeout =3D PXEBC_DEFAULT_LIFETIME; + Ip6CfgData->TransmitTimeout =3D PXEBC_DEFAULT_LIFETIME; + + return EFI_SUCCESS; + +ON_ERROR: + PxeBcDestroyIp6Children (This, Private); + return Status; +} + + +/** + The entry point for UefiPxeBc driver that installs the driver + binding and component name protocol on its image. + + @param[in] ImageHandle The Image handle of the driver. + @param[in] SystemTable The system table. + + @return EFI_SUCCESS + @return Others + +**/ +EFI_STATUS +EFIAPI +PxeBcDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + Status =3D EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gPxeBcIp4DriverBinding, + ImageHandle, + &gPxeBcComponentName, + &gPxeBcComponentName2 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status =3D EfiLibInstallDriverBindingComponentName2 ( + ImageHandle, + SystemTable, + &gPxeBcIp6DriverBinding, + NULL, + &gPxeBcComponentName, + &gPxeBcComponentName2 + ); + if (EFI_ERROR (Status)) { + gBS->UninstallMultipleProtocolInterfaces ( + ImageHandle, + &gEfiDriverBindingProtocolGuid, + &gPxeBcIp4DriverBinding, + &gEfiComponentName2ProtocolGuid, + &gPxeBcComponentName2, + &gEfiComponentNameProtocolGuid, + &gPxeBcComponentName, + NULL + ); + } + + return Status; +} + +/** + Test to see if this driver supports ControllerHandle. This is the worker= function for + PxeBcIp4(6)DriverBindingSupported. + + @param[in] This The pointer to the driver binding protoc= ol. + @param[in] ControllerHandle The handle of device to be tested. + @param[in] RemainingDevicePath Optional parameter used to pick a specif= ic child + device to be started. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + =20 + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN UINT8 IpVersion + ) +{ + EFI_STATUS Status; + EFI_GUID *DhcpServiceBindingGuid; + EFI_GUID *MtftpServiceBindingGuid; + =20 + if (IpVersion =3D=3D IP_VERSION_4) { + DhcpServiceBindingGuid =3D &gEfiDhcp4ServiceBindingProtocolGuid; + MtftpServiceBindingGuid =3D &gEfiMtftp4ServiceBindingProtocolGuid; + } else { + DhcpServiceBindingGuid =3D &gEfiDhcp6ServiceBindingProtocolGuid; + MtftpServiceBindingGuid =3D &gEfiMtftp6ServiceBindingProtocolGuid; + } + + // + // Try to open the Mtftp and Dhcp protocol to test whether IP stack is r= eady. + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + DhcpServiceBindingGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + Status =3D gBS->OpenProtocol ( + ControllerHandle, + MtftpServiceBindingGuid, + NULL, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_TEST_PROTOCOL + ); + } + + // + // It's unsupported case if IP stack are not ready. + // + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +/** + Start this driver on ControllerHandle. This is the worker function for + PxeBcIp4(6)DriverBindingStart. + + @param[in] This The pointer to the driver binding proto= col. + @param[in] ControllerHandle The handle of device to be started. + @param[in] RemainingDevicePath Optional parameter used to pick a speci= fic child + device to be started. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + + @retval EFI_SUCCESS This driver is installed to ControllerHandl= e. + @retval EFI_ALREADY_STARTED This driver is already running on Controlle= rHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL, + IN UINT8 IpVersion + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_STATUS Status; + PXEBC_PRIVATE_PROTOCOL *Id; + BOOLEAN FirstStart; + + FirstStart =3D FALSE; + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (!EFI_ERROR (Status)) { + // + // Skip the initialization if the driver has been started already. + // + Private =3D PXEBC_PRIVATE_DATA_FROM_ID (Id); + } else { + FirstStart =3D TRUE; + // + // If the driver has not been started yet, it should do initialization= . + // + Private =3D AllocateZeroPool (sizeof (PXEBC_PRIVATE_DATA)); + if (Private =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem ( + &Private->PxeBc, + &gPxeBcProtocolTemplate, + sizeof (EFI_PXE_BASE_CODE_PROTOCOL) + ); + + Private->Signature =3D PXEBC_PRIVATE_DATA_SIGNATURE; + Private->Controller =3D ControllerHandle; + Private->Image =3D This->ImageHandle; + Private->PxeBc.Mode =3D &Private->Mode; + Private->Mode.Ipv6Supported =3D TRUE; + Private->Mode.AutoArp =3D TRUE; + Private->Mode.TTL =3D DEFAULT_TTL; + Private->Mode.ToS =3D DEFAULT_ToS; + + // + // Open device path to prepare for appending virtual NIC node. + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiDevicePathProtocolGuid, + (VOID **) &Private->DevicePath, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Get the NII interface if it exists, it's not required. + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiNetworkInterfaceIdentifierProtocolGuid_31, + (VOID **) &Private->Nii, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + Private->Nii =3D NULL; + } + + // + // Install PxeBaseCodePrivate protocol onto the real NIC handler. + // PxeBaseCodePrivate protocol is only used to keep the relationship b= etween=20 + // NIC handle and virtual child handles. + // gEfiCallerIdGuid will be used as its protocol guid. + // + Status =3D gBS->InstallProtocolInterface ( + &ControllerHandle, + &gEfiCallerIdGuid, + EFI_NATIVE_INTERFACE, + &Private->Id + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Try to locate SNP protocol. + // + NetLibGetSnpHandle(ControllerHandle, &Private->Snp); =20 + } + + if (IpVersion =3D=3D IP_VERSION_4) { + // + // Try to create virtual NIC handle for IPv4. + // + Status =3D PxeBcCreateIp4Children (This, ControllerHandle, Private); + } else { + // + // Try to create virtual NIC handle for IPv6. + // + Status =3D PxeBcCreateIp6Children (This, ControllerHandle, Private); + } + if (EFI_ERROR (Status)) { + // + // Failed to start PXE driver if IPv4 and IPv6 stack are both not avai= lable. + // + Status =3D EFI_DEVICE_ERROR; + goto ON_ERROR; + } + + return EFI_SUCCESS; + +ON_ERROR: + if (FirstStart) { + gBS->UninstallProtocolInterface ( + ControllerHandle, + &gEfiCallerIdGuid, + &Private->Id + ); + } + + if (IpVersion =3D=3D IP_VERSION_4) { + PxeBcDestroyIp4Children (This, Private); + } else { + PxeBcDestroyIp6Children (This, Private); + } + + if (FirstStart && Private !=3D NULL) { + FreePool (Private); + } + + return Status; +} + + +/** + Stop this driver on ControllerHandle. This is the worker function for + PxeBcIp4(6)DriverBindingStop. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on. + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If= number of + children is zero stop the entire bus drive= r. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. + + @retval EFI_SUCCESS This driver was removed ControllerHandle. + @retval EFI_DEVICE_ERROR An unexpected system or network error occu= rred. + @retval Others This driver was not removed from this devi= ce + +**/ +EFI_STATUS +EFIAPI +PxeBcStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer, + IN UINT8 IpVersion + ) +{ + PXEBC_PRIVATE_DATA *Private; + PXEBC_VIRTUAL_NIC *VirtualNic; + EFI_LOAD_FILE_PROTOCOL *LoadFile; + EFI_STATUS Status; + EFI_HANDLE NicHandle; + PXEBC_PRIVATE_PROTOCOL *Id; + + Private =3D NULL; + NicHandle =3D NULL; + VirtualNic =3D NULL; + LoadFile =3D NULL; + Id =3D NULL; + + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiLoadFileProtocolGuid, + (VOID **) &LoadFile, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + // + // Get the Nic handle by any pass-over service child handle. + // + if (IpVersion =3D=3D IP_VERSION_4) { + NicHandle =3D PxeBcGetNicByIp4Children (ControllerHandle); + } else { + NicHandle =3D PxeBcGetNicByIp6Children (ControllerHandle); + } + if (NicHandle =3D=3D NULL) { + return EFI_SUCCESS; + } + + // + // Try to retrieve the private data by PxeBcPrivate protocol. + // + Status =3D gBS->OpenProtocol ( + NicHandle, + &gEfiCallerIdGuid, + (VOID **) &Id, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + Private =3D PXEBC_PRIVATE_DATA_FROM_ID (Id); + + } else { + // + // It's a virtual handle with LoadFileProtocol. + // + Status =3D gBS->OpenProtocol ( + ControllerHandle, + &gEfiLoadFileProtocolGuid, + (VOID **) &LoadFile, + This->DriverBindingHandle, + ControllerHandle, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + VirtualNic =3D PXEBC_VIRTUAL_NIC_FROM_LOADFILE (LoadFile); + Private =3D VirtualNic->Private; + NicHandle =3D Private->Controller; + } + + // + // Stop functionality of PXE Base Code protocol + // + Status =3D Private->PxeBc.Stop (&Private->PxeBc); + if (Status !=3D EFI_SUCCESS && Status !=3D EFI_NOT_STARTED) { + return Status; + } + + + if (Private->Ip4Nic !=3D NULL && IpVersion =3D=3D IP_VERSION_4) { + PxeBcDestroyIp4Children (This, Private); + } + + if (Private->Ip6Nic !=3D NULL && IpVersion =3D=3D IP_VERSION_6) { + PxeBcDestroyIp6Children (This, Private); + } + + if (Private->Ip4Nic =3D=3D NULL && Private->Ip6Nic =3D=3D NULL) { + gBS->UninstallProtocolInterface ( + NicHandle, + &gEfiCallerIdGuid, + &Private->Id + ); + FreePool (Private); + } + + return EFI_SUCCESS; +} + +/** + Test to see if this driver supports ControllerHandle. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding protoc= ol. + @param[in] ControllerHandle The handle of device to be tested. + @param[in] RemainingDevicePath Optional parameter used to pick a specif= ic child + device to be started. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp4DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return PxeBcSupported ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_4 + ); +} + +/** + Start this driver on ControllerHandle. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding proto= col. + @param[in] ControllerHandle The handle of device to be started. + @param[in] RemainingDevicePath Optional parameter used to pick a speci= fic child + device to be started. + + @retval EFI_SUCCESS This driver is installed to ControllerHandl= e. + @retval EFI_ALREADY_STARTED This driver is already running on Controlle= rHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp4DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return PxeBcStart ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_4 + ); +} + +/** + Stop this driver on ControllerHandle. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If= number of + children is zero stop the entire bus drive= r. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval EFI_DEVICE_ERROR An unexpected system or network error occu= rred. + @retval Others This driver was not removed from this devi= ce. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp4DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + return PxeBcStop ( + This, + ControllerHandle, + NumberOfChildren, + ChildHandleBuffer, + IP_VERSION_4 + ); +} + +/** + Test to see if this driver supports ControllerHandle. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding protoc= ol. + @param[in] ControllerHandle The handle of device to be tested. + @param[in] RemainingDevicePath Optional parameter use to pick a specifi= c child + device to be started. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return PxeBcSupported ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_6 + ); +} + +/** + Start this driver on ControllerHandle. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding proto= col. + @param[in] ControllerHandle The handle of device to be started. + @param[in] RemainingDevicePath Optional parameter used to pick a speci= fic child + device to be started. + + @retval EFI_SUCCESS This driver is installed to ControllerHandl= e. + @retval EFI_ALREADY_STARTED This driver is already running on Controlle= rHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ) +{ + return PxeBcStart ( + This, + ControllerHandle, + RemainingDevicePath, + IP_VERSION_6 + ); +} + +/** + Stop this driver on ControllerHandle. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If= number of + children is zero stop the entire bus drive= r. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval EFI_DEVICE_ERROR An unexpected system or network error occu= rred. + @retval Others This driver was not removed from this devi= ce. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp6DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ) +{ + return PxeBcStop ( + This, + ControllerHandle, + NumberOfChildren, + ChildHandleBuffer, + IP_VERSION_6 + ); +} diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcDriver.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/Netwo= rkPkg/UefiPxeBcDxe/PxeBcDriver.h new file mode 100644 index 0000000..5d040b7 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcDriver.h @@ -0,0 +1,181 @@ +/** @file + Driver Binding functions declaration for UefiPxeBc Driver. + + Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __EFI_PXEBC_DRIVER_H__ +#define __EFI_PXEBC_DRIVER_H__ + +extern EFI_COMPONENT_NAME_PROTOCOL gPxeBcComponentName; +extern EFI_COMPONENT_NAME2_PROTOCOL gPxeBcComponentName2; + +/** + Test to see if this driver supports ControllerHandle. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding protoc= ol. + @param[in] ControllerHandle The handle of device to be tested. + @param[in] RemainingDevicePath Optional parameter use to pick a specifi= c child + device to be started. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp4DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Start this driver on ControllerHandle. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding proto= col. + @param[in] ControllerHandle The handle of device to be started. + @param[in] RemainingDevicePath Optional parameter used to pick a speci= fic child + device to be started. + + @retval EFI_SUCCESS This driver is installed to ControllerHandl= e. + @retval EFI_ALREADY_STARTED This driver is already running on Controlle= rHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp4DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + + +/** + Stop this driver on ControllerHandle. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If= number of + children is zero stop the entire bus drive= r. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval EFI_DEVICE_ERROR An unexpected system or network error occu= rred. + @retval Others This driver was not removed from this devi= ce. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp4DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +/** + Test to see if this driver supports ControllerHandle. This service + is called by the EFI boot service ConnectController(). In + order to make drivers as small as possible, there are a few calling + restrictions for this service. ConnectController() must + follow these calling restrictions. If any other agent wishes to call + Supported() it must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding protoc= ol. + @param[in] ControllerHandle The handle of device to be tested. + @param[in] RemainingDevicePath Optional parameter use to pick a specifi= c child + device to be started. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp6DriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Start this driver on ControllerHandle. This service is called by the + EFI boot service ConnectController(). In order to make + drivers as small as possible, there are a few calling restrictions for + this service. ConnectController() must follow these + calling restrictions. If any other agent wishes to call Start() it + must also follow these calling restrictions. + + @param[in] This The pointer to the driver binding proto= col. + @param[in] ControllerHandle The handle of device to be started. + @param[in] RemainingDevicePath Optional parameter used to pick a speci= fic child + device to be started. + + @retval EFI_SUCCESS This driver is installed to ControllerHandl= e. + @retval EFI_ALREADY_STARTED This driver is already running on Controlle= rHandle. + @retval other This driver does not support this device. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp6DriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL + ); + +/** + Stop this driver on ControllerHandle. This service is called by the + EFI boot service DisconnectController(). In order to + make drivers as small as possible, there are a few calling + restrictions for this service. DisconnectController() + must follow these calling restrictions. If any other agent wishes + to call Stop() it must also follow these calling restrictions. + + @param[in] This Protocol instance pointer. + @param[in] ControllerHandle Handle of device to stop driver on + @param[in] NumberOfChildren Number of Handles in ChildHandleBuffer. If= number of + children is zero stop the entire bus drive= r. + @param[in] ChildHandleBuffer List of Child Handles to Stop. + + @retval EFI_SUCCESS This driver is removed ControllerHandle + @retval EFI_DEVICE_ERROR An unexpected system or network error occu= rred. + @retval Others This driver was not removed from this devi= ce. + +**/ +EFI_STATUS +EFIAPI +PxeBcIp6DriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE ControllerHandle, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); +#endif + diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcImpl.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Network= Pkg/UefiPxeBcDxe/PxeBcImpl.c new file mode 100644 index 0000000..bda4d16 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcImpl.c @@ -0,0 +1,2411 @@ +/** @file + This implementation of EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROT= OCOL. + + Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + + +/** + Enables the use of the PXE Base Code Protocol functions. + + This function enables the use of the PXE Base Code Protocol functions. I= f the + Started field of the EFI_PXE_BASE_CODE_MODE structure is already TRUE, t= hen + EFI_ALREADY_STARTED will be returned. If UseIpv6 is TRUE, then IPv6 form= atted + addresses will be used in this session. If UseIpv6 is FALSE, then IPv4 f= ormatted + addresses will be used in this session. If UseIpv6 is TRUE, and the Ipv6= Supported + field of the EFI_PXE_BASE_CODE_MODE structure is FALSE, then EFI_UNSUPPO= RTED will + be returned. If there is not enough memory or other resources to start t= he PXE + Base Code Protocol, then EFI_OUT_OF_RESOURCES will be returned. Otherwis= e, the + PXE Base Code Protocol will be started. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] UseIpv6 Specifies the type of IP addresses that ar= e to be + used during the session that is being star= ted. + Set to TRUE for IPv6, and FALSE for IPv4. + + @retval EFI_SUCCESS The PXE Base Code Protocol was started. + @retval EFI_DEVICE_ERROR The network device encountered an error du= ring this operation. + @retval EFI_UNSUPPORTED UseIpv6 is TRUE, but the Ipv6Supported fie= ld of the + EFI_PXE_BASE_CODE_MODE structure is FALSE. + @retval EFI_ALREADY_STARTED The PXE Base Code Protocol is already in t= he started state. + @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not poi= nt to a valid + EFI_PXE_BASE_CODE_PROTOCOL structure. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough memory or other = resources to start the + PXE Base Code Protocol. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcStart ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN UseIpv6 + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + UINTN Index; + EFI_STATUS Status; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + + if (Mode->Started) { + return EFI_ALREADY_STARTED; + } + + // + // Detect whether using IPv6 or not, and set it into mode data. + // + if (UseIpv6 && Mode->Ipv6Available && Mode->Ipv6Supported && Private->Ip= 6Nic !=3D NULL) { + Mode->UsingIpv6 =3D TRUE; + } else if (!UseIpv6 && Private->Ip4Nic !=3D NULL) { + Mode->UsingIpv6 =3D FALSE; + } else { + return EFI_UNSUPPORTED; + } + + if (Mode->UsingIpv6) { + AsciiPrint ("\n>>Start PXE over IPv6"); + // + // Configure udp6 instance to receive data. + // + Status =3D Private->Udp6Read->Configure ( + Private->Udp6Read, + &Private->Udp6CfgData + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + =20 + // + // Configure block size for TFTP as a default value to handle all link= layers. + // + Private->BlockSize =3D (UINTN) (Private->Ip6MaxPacketSize - + PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT= _TFTP_OVERHEAD_SIZE); + + // + // PXE over IPv6 starts here, initialize the fields and list header. + // + Private->Ip6Policy =3D PXEBC_IP6_POLICY_MAX; + Private->ProxyOffer.Dhcp6.Packet.Offer.Size =3D PXEBC_DHCP6_PACKET_MAX= _SIZE; + Private->DhcpAck.Dhcp6.Packet.Ack.Size =3D PXEBC_DHCP6_PACKET_MAX= _SIZE; + Private->PxeReply.Dhcp6.Packet.Ack.Size =3D PXEBC_DHCP6_PACKET_MAX= _SIZE; + + for (Index =3D 0; Index < PXEBC_OFFER_MAX_NUM; Index++) { + Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size =3D PXEBC_DHCP6_= PACKET_MAX_SIZE; + } + + // + // Create event and set status for token to capture ICMP6 error messag= e. + // + Private->Icmp6Token.Status =3D EFI_NOT_READY; + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcIcmp6ErrorUpdate, + Private, + &Private->Icmp6Token.Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Set Ip6 policy to Automatic to start the IP6 router discovery. + // + Status =3D PxeBcSetIp6Policy (Private); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } else { + AsciiPrint ("\n>>Start PXE over IPv4"); + // + // Configure udp4 instance to receive data. + // + Status =3D Private->Udp4Read->Configure ( + Private->Udp4Read, + &Private->Udp4CfgData + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + =20 + // + // Configure block size for TFTP as a default value to handle all link= layers. + // + Private->BlockSize =3D (UINTN) (Private->Ip4MaxPacketSize - + PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT= _TFTP_OVERHEAD_SIZE); + + // + // PXE over IPv4 starts here, initialize the fields. + // + Private->ProxyOffer.Dhcp4.Packet.Offer.Size =3D PXEBC_DHCP4_PACKET_MAX= _SIZE; + Private->DhcpAck.Dhcp4.Packet.Ack.Size =3D PXEBC_DHCP4_PACKET_MAX= _SIZE; + Private->PxeReply.Dhcp4.Packet.Ack.Size =3D PXEBC_DHCP4_PACKET_MAX= _SIZE; + + for (Index =3D 0; Index < PXEBC_OFFER_MAX_NUM; Index++) { + Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size =3D PXEBC_DHCP4_= PACKET_MAX_SIZE; + } + + PxeBcSeedDhcp4Packet (&Private->SeedPacket, Private->Udp4Read); + + // + // Create the event for Arp cache update. + // + Status =3D gBS->CreateEvent ( + EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + PxeBcArpCacheUpdate, + Private, + &Private->ArpUpdateEvent + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Start a periodic timer by second to update Arp cache. + // + Status =3D gBS->SetTimer ( + Private->ArpUpdateEvent, + TimerPeriodic, + TICKS_PER_SECOND + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Create event and set status for token to capture ICMP error message= . + // + Private->Icmp6Token.Status =3D EFI_NOT_READY; + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcIcmpErrorUpdate, + Private, + &Private->IcmpToken.Event + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + //DHCP4 service allows only one of its children to be configured in =20 + //the active state, If the DHCP4 D.O.R.A started by IP4 auto =20 + //configuration and has not been completed, the Dhcp4 state machine=20 + //will not be in the right state for the PXE to start a new round D.O.= R.A.=20 + //so we need to switch it's policy to static. + // + Status =3D PxeBcSetIp4Policy (Private); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + } + + // + // If PcdTftpBlockSize is set to non-zero, override the default value. + // + if (PcdGet64 (PcdTftpBlockSize) !=3D 0) { + Private->BlockSize =3D (UINTN) PcdGet64 (PcdTftpBlockSize); + } + + // + // Create event for UdpRead/UdpWrite timeout since they are both blockin= g API. + // + Status =3D gBS->CreateEvent ( + EVT_TIMER, + TPL_CALLBACK, + NULL, + NULL, + &Private->UdpTimeOutEvent + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + Private->IsAddressOk =3D FALSE; + Mode->Started =3D TRUE; + + return EFI_SUCCESS; + +ON_ERROR: + if (Mode->UsingIpv6) { + if (Private->Icmp6Token.Event !=3D NULL) { + gBS->CloseEvent (Private->Icmp6Token.Event); + Private->Icmp6Token.Event =3D NULL; + } + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + Private->Ip6->Configure (Private->Ip6, NULL); + } else { + if (Private->ArpUpdateEvent !=3D NULL) { + gBS->CloseEvent (Private->ArpUpdateEvent); + Private->ArpUpdateEvent =3D NULL; + } + if (Private->IcmpToken.Event !=3D NULL) { + gBS->CloseEvent (Private->IcmpToken.Event); + Private->IcmpToken.Event =3D NULL; + } + Private->Udp4Read->Configure (Private->Udp4Read, NULL); + Private->Ip4->Configure (Private->Ip4, NULL); + } + return Status; +} + + +/** + Disable the use of the PXE Base Code Protocol functions. + + This function stops all activity on the network device. All the resource= s allocated + in Start() are released, the Started field of the EFI_PXE_BASE_CODE_MODE= structure is + set to FALSE, and EFI_SUCCESS is returned. If the Started field of the E= FI_PXE_BASE_CODE_MODE + structure is already FALSE, then EFI_NOT_STARTED will be returned. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL= instance. + + @retval EFI_SUCCESS The PXE Base Code Protocol was stopped. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is already in t= he stopped state. + @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not poi= nt to a valid + EFI_PXE_BASE_CODE_PROTOCOL structure. + @retval Others + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcStop ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + BOOLEAN Ipv6Supported; + BOOLEAN Ipv6Available; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + Ipv6Supported =3D Mode->Ipv6Supported; + Ipv6Available =3D Mode->Ipv6Available; + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + if (Mode->UsingIpv6) { + // + // Configure all the instances for IPv6 as NULL. + // + ZeroMem (&Private->Udp6CfgData.StationAddress, sizeof (EFI_IPv6_ADDRES= S)); + ZeroMem (&Private->Ip6CfgData.StationAddress, sizeof (EFI_IPv6_ADDRESS= )); + Private->Dhcp6->Stop (Private->Dhcp6); + Private->Dhcp6->Configure (Private->Dhcp6, NULL); + Private->Udp6Write->Configure (Private->Udp6Write, NULL); + Private->Udp6Read->Groups (Private->Udp6Read, FALSE, NULL); + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token); + Private->Ip6->Configure (Private->Ip6, NULL); + PxeBcUnregisterIp6Address (Private); + if (Private->Icmp6Token.Event !=3D NULL) { + gBS->CloseEvent (Private->Icmp6Token.Event); + Private->Icmp6Token.Event =3D NULL; + } + if (Private->Dhcp6Request !=3D NULL) { + FreePool (Private->Dhcp6Request); + Private->Dhcp6Request =3D NULL; + } + if (Private->BootFileName !=3D NULL) { + FreePool (Private->BootFileName); + Private->BootFileName =3D NULL; + } + } else { + // + // Configure all the instances for IPv4 as NULL. + // + ZeroMem (&Private->Udp4CfgData.StationAddress, sizeof (EFI_IPv4_ADDRES= S)); + ZeroMem (&Private->Udp4CfgData.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); + ZeroMem (&Private->Ip4CfgData.StationAddress, sizeof (EFI_IPv4_ADDRESS= )); + ZeroMem (&Private->Ip4CfgData.SubnetMask, sizeof (EFI_IPv4_ADDRESS)); + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); + Private->Udp4Write->Configure (Private->Udp4Write, NULL); + Private->Udp4Read->Groups (Private->Udp4Read, FALSE, NULL); + Private->Udp4Read->Configure (Private->Udp4Read, NULL); + Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken); + Private->Ip4->Configure (Private->Ip4, NULL); + if (Private->ArpUpdateEvent !=3D NULL) { + gBS->CloseEvent (Private->ArpUpdateEvent); + Private->ArpUpdateEvent =3D NULL; + } + if (Private->IcmpToken.Event !=3D NULL) { + gBS->CloseEvent (Private->IcmpToken.Event); + Private->IcmpToken.Event =3D NULL; + } + Private->BootFileName =3D NULL; + } + + gBS->CloseEvent (Private->UdpTimeOutEvent); + Private->CurSrcPort =3D 0; + Private->BootFileSize =3D 0; + Private->SolicitTimes =3D 0; + Private->ElapsedTime =3D 0; + ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS)); + + // + // Reset the mode data. + // + ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE)); + Mode->Ipv6Available =3D Ipv6Available; + Mode->Ipv6Supported =3D Ipv6Supported; + Mode->AutoArp =3D TRUE; + Mode->TTL =3D DEFAULT_TTL; + Mode->ToS =3D DEFAULT_ToS; + + return EFI_SUCCESS; +} + + +/** + Attempts to complete a DHCPv4 D.O.R.A. (discover / offer / request / ack= nowledge) or DHCPv6 + S.A.R.R (solicit / advertise / request / reply) sequence. + + If SortOffers is TRUE, then the cached DHCP offer packets will be sorted= before + they are tried. If SortOffers is FALSE, then the cached DHCP offer packe= ts will + be tried in the order in which they are received. Please see the Preboot= Execution + Environment (PXE) Specification and Unified Extensible Firmware Interfac= e (UEFI) + Specification for additional details on the implementation of DHCP. + If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STAT= US_CONTINUE, + then the DHCP sequence will be stopped and EFI_ABORTED will be returned. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] SortOffers TRUE if the offers received should be sort= ed. Set to FALSE to + try the offers in the order that they are = received. + + @retval EFI_SUCCESS Valid DHCP has completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER The This parameter is NULL or does not poi= nt to a valid + EFI_PXE_BASE_CODE_PROTOCOL structure. + @retval EFI_DEVICE_ERROR The network device encountered an error du= ring this operation. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough memory to comple= te the DHCP Protocol. + @retval EFI_ABORTED The callback function aborted the DHCP Pro= tocol. + @retval EFI_TIMEOUT The DHCP Protocol timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during t= he DHCP session. + @retval EFI_NO_RESPONSE Valid PXE offer was not received. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcDhcp ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN SortOffers + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_STATUS Status; + EFI_PXE_BASE_CODE_IP_FILTER IpFilter; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Status =3D EFI_SUCCESS; + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + Mode->IcmpErrorReceived =3D FALSE; + Private->Function =3D EFI_PXE_BASE_CODE_FUNCTION_DHCP; + Private->IsOfferSorted =3D SortOffers; + Private->SolicitTimes =3D 0; + Private->ElapsedTime =3D 0; + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + if (Mode->UsingIpv6) { + + // + // Stop Udp6Read instance + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + + // + // Start S.A.R.R. process to get a IPv6 address and other boot informa= tion. + // + Status =3D PxeBcDhcp6Sarr (Private, Private->Dhcp6); + } else { + + // + // Stop Udp4Read instance + // + Private->Udp4Read->Configure (Private->Udp4Read, NULL); + + // + // Start D.O.R.A. process to get a IPv4 address and other boot informa= tion. + // + Status =3D PxeBcDhcp4Dora (Private, Private->Dhcp4); + } + + // + // Reconfigure the UDP instance with the default configuration. + // + if (Mode->UsingIpv6) { + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData= ); + } else { + Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData= ); + } + // + // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with th= e IP + // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_I= P_FILTER_STATION_IP. + // + ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER)); + IpFilter.Filters =3D EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP; + This->SetIpFilter (This, &IpFilter); + + return Status; +} + + +/** + Attempts to complete the PXE Boot Server and/or boot image discovery seq= uence. + + This function attempts to complete the PXE Boot Server and/or boot image= discovery + sequence. If this sequence is completed, then EFI_SUCCESS is returned, a= nd the + PxeDiscoverValid, PxeDiscover, PxeReplyReceived, and PxeReply fields of = the + EFI_PXE_BASE_CODE_MODE structure are filled in. If UseBis is TRUE, then = the + PxeBisReplyReceived and PxeBisReply fields of the EFI_PXE_BASE_CODE_MODE= structure + will also be filled in. If UseBis is FALSE, then PxeBisReplyValid will b= e set to FALSE. + In the structure referenced by parameter Info, the PXE Boot Server list,= SrvList[], + has two uses: It is the Boot Server IP address list used for unicast dis= covery + (if the UseUCast field is TRUE), and it is the list used for Boot Server= verification + (if the MustUseList field is TRUE). Also, if the MustUseList field in th= at structure + is TRUE and the AcceptAnyResponse field in the SrvList[] array is TRUE, = any Boot + Server reply of that type will be accepted. If the AcceptAnyResponse fie= ld is + FALSE, only responses from Boot Servers with matching IP addresses will = be accepted. + This function can take at least 10 seconds to timeout and return control= to the + caller. If the Discovery sequence does not complete, then EFI_TIMEOUT wi= ll be + returned. Please see the Preboot Execution Environment (PXE) Specificati= on for + additional details on the implementation of the Discovery sequence. + If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STAT= US_CONTINUE, + then the Discovery sequence is stopped and EFI_ABORTED will be returned. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] Type The type of bootstrap to perform. + @param[in] Layer Pointer to the boot server layer number to= discover, which must be + PXE_BOOT_LAYER_INITIAL when a new server t= ype is being + discovered. + @param[in] UseBis TRUE if Boot Integrity Services are to be = used. FALSE otherwise. + @param[in] Info Pointer to a data structure that contains = additional information + on the type of discovery operation that is= to be performed. + It is optional. + + @retval EFI_SUCCESS The Discovery sequence has been completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error du= ring this operation. + @retval EFI_OUT_OF_RESOURCES Could not allocate enough memory to comple= te Discovery. + @retval EFI_ABORTED The callback function aborted the Discover= y sequence. + @retval EFI_TIMEOUT The Discovery sequence timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during t= he PXE discovery + session. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcDiscover ( + 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 + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_PXE_BASE_CODE_DISCOVER_INFO DefaultInfo; + EFI_PXE_BASE_CODE_SRVLIST *SrvList; + PXEBC_BOOT_SVR_ENTRY *BootSvrEntry; + UINT16 Index; + EFI_STATUS Status; + EFI_PXE_BASE_CODE_IP_FILTER IpFilter; + EFI_PXE_BASE_CODE_DISCOVER_INFO *NewCreatedInfo; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + Mode->IcmpErrorReceived =3D FALSE; + BootSvrEntry =3D NULL; + SrvList =3D NULL; + Status =3D EFI_DEVICE_ERROR; + Private->Function =3D EFI_PXE_BASE_CODE_FUNCTION_DISCOVER; + NewCreatedInfo =3D NULL; + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + // + // Station address should be ready before do discover. + // + if (!Private->IsAddressOk) { + return EFI_INVALID_PARAMETER; + } + + if (Mode->UsingIpv6) { + + // + // Stop Udp6Read instance + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + } else { + + // + // Stop Udp4Read instance + // + Private->Udp4Read->Configure (Private->Udp4Read, NULL); + } + + // + // There are 3 methods to get the information for discover. + // + ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO)); + if (*Layer !=3D EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) { + // + // 1. Take the previous setting as the discover info. + // + if (!Mode->PxeDiscoverValid || + !Mode->PxeReplyReceived || + (!Mode->PxeBisReplyReceived && UseBis)) { + Status =3D EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Info =3D &DefaultInfo; + Info->IpCnt =3D 1; + Info->UseUCast =3D TRUE; + SrvList =3D Info->SrvList; + SrvList[0].Type =3D Type; + SrvList[0].AcceptAnyResponse =3D FALSE; + + CopyMem (&SrvList->IpAddr, &Private->ServerIp, sizeof (EFI_IP_ADDRESS)= ); + + } else if (Info =3D=3D NULL) { + // + // 2. Extract the discover information from the cached packets if unsp= ecified. + // + NewCreatedInfo =3D &DefaultInfo; + Status =3D PxeBcExtractDiscoverInfo (Private, Type, &NewCreatedInfo, &= BootSvrEntry, &SrvList); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + ASSERT (NewCreatedInfo !=3D NULL); + Info =3D NewCreatedInfo; + } else { + // + // 3. Take the pass-in information as the discover info, and validate = the server list. + // + SrvList =3D Info->SrvList; + + if (!SrvList[0].AcceptAnyResponse) { + for (Index =3D 1; Index < Info->IpCnt; Index++) { + if (SrvList[Index].AcceptAnyResponse) { + break; + } + } + if (Index !=3D Info->IpCnt) { + // + // It's invalid if the first server doesn't accecpt any response + // but any of the other servers does accept any response. + // + Status =3D EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + } + } + + // + // Info and BootSvrEntry/SrvList are all ready by now, so execute discov= er by UniCast/BroadCast/MultiCast. + // + if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) || + (Info->MustUseList && Info->IpCnt =3D=3D 0)) { + Status =3D EFI_INVALID_PARAMETER; + goto ON_EXIT; + } + + Private->IsDoDiscover =3D TRUE; + + if (Info->UseMCast) { + // + // Do discover by multicast. + // + Status =3D PxeBcDiscoverBootServer ( + Private, + Type, + Layer, + UseBis, + &Info->ServerMCastIp, + Info->IpCnt, + SrvList + ); + + } else if (Info->UseBCast) { + // + // Do discover by broadcast, but only valid for IPv4. + // + ASSERT (!Mode->UsingIpv6); + Status =3D PxeBcDiscoverBootServer ( + Private, + Type, + Layer, + UseBis, + NULL, + Info->IpCnt, + SrvList + ); + + } else if (Info->UseUCast) { + // + // Do discover by unicast. + // + for (Index =3D 0; Index < Info->IpCnt; Index++) { + if (BootSvrEntry =3D=3D NULL) { + CopyMem (&Private->ServerIp, &SrvList[Index].IpAddr, sizeof (EFI_I= P_ADDRESS)); + } else { + ASSERT (!Mode->UsingIpv6); + ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof = (EFI_IPv4_ADDRESS)); + } + + Status =3D PxeBcDiscoverBootServer ( + Private, + Type, + Layer, + UseBis, + &Private->ServerIp, + Info->IpCnt, + SrvList + ); + } + } + + if (!EFI_ERROR (Status)) { + // + // Parse the cached PXE reply packet, and store it into mode data if v= alid. + // + if (Mode->UsingIpv6) { + Status =3D PxeBcParseDhcp6Packet (&Private->PxeReply.Dhcp6); + if (!EFI_ERROR (Status)) { + CopyMem ( + &Mode->PxeReply.Dhcpv6, + &Private->PxeReply.Dhcp6.Packet.Ack.Dhcp6, + Private->PxeReply.Dhcp6.Packet.Ack.Length + ); + Mode->PxeReplyReceived =3D TRUE; + Mode->PxeDiscoverValid =3D TRUE; + } + } else { + Status =3D PxeBcParseDhcp4Packet (&Private->PxeReply.Dhcp4); + if (!EFI_ERROR (Status)) { + CopyMem ( + &Mode->PxeReply.Dhcpv4, + &Private->PxeReply.Dhcp4.Packet.Ack.Dhcp4, + Private->PxeReply.Dhcp4.Packet.Ack.Length + ); + Mode->PxeReplyReceived =3D TRUE; + Mode->PxeDiscoverValid =3D TRUE; + } + } + } + +ON_EXIT: + + if (NewCreatedInfo !=3D NULL && NewCreatedInfo !=3D &DefaultInfo) { + FreePool (NewCreatedInfo); + } + =20 + if (Mode->UsingIpv6) { + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData= ); + } else { + Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData= ); + } + =20 + // + // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with th= e IP + // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_I= P_FILTER_STATION_IP. + // + ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER)); + IpFilter.Filters =3D EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP; + This->SetIpFilter (This, &IpFilter); + + return Status; +} + + +/** + Used to perform TFTP and MTFTP services. + + This function is used to perform TFTP and MTFTP services. This includes = the + TFTP operations to get the size of a file, read a directory, read a file= , and + write a file. It also includes the MTFTP operations to get the size of a= file, + read a directory, and read a file. The type of operation is specified by= Operation. + If the callback function that is invoked during the TFTP/MTFTP operation= does + not return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED = will + be returned. + For read operations, the return data will be placed in the buffer specif= ied by + BufferPtr. If BufferSize is too small to contain the entire downloaded f= ile, + then EFI_BUFFER_TOO_SMALL will be returned and BufferSize will be set to= zero, + or the size of the requested file. (NOTE: the size of the requested file= is only returned + if the TFTP server supports TFTP options). If BufferSize is large enough= for the + read operation, then BufferSize will be set to the size of the downloade= d file, + and EFI_SUCCESS will be returned. Applications using the PxeBc.Mtftp() s= ervices + should use the get-file-size operations to determine the size of the dow= nloaded + file prior to using the read-file operations-especially when downloading= large + (greater than 64 MB) files-instead of making two calls to the read-file = operation. + Following this recommendation will save time if the file is larger than = expected + and the TFTP server does not support TFTP option extensions. Without TFT= P option + extension support, the client must download the entire file, counting an= d discarding + the received packets, to determine the file size. + For write operations, the data to be sent is in the buffer specified by = BufferPtr. + BufferSize specifies the number of bytes to send. If the write operation= completes + successfully, then EFI_SUCCESS will be returned. + For TFTP "get file size" operations, the size of the requested file or d= irectory + is returned in BufferSize, and EFI_SUCCESS will be returned. If the TFTP= server + does not support options, the file will be downloaded into a bit bucket = and the + length of the downloaded file will be returned. For MTFTP "get file size= " operations, + if the MTFTP server does not support the "get file size" option, EFI_UNS= UPPORTED + will be returned. + This function can take up to 10 seconds to timeout and return control to= the caller. + If the TFTP sequence does not complete, EFI_TIMEOUT will be returned. + If the Callback Protocol does not return EFI_PXE_BASE_CODE_CALLBACK_STAT= US_CONTINUE, + then the TFTP sequence is stopped and EFI_ABORTED will be returned. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] Operation The type of operation to perform. + @param[in, out] BufferPtr A pointer to the data buffer. + @param[in] Overwrite Only used on write file operations. TRUE i= f a file on a remote + server can be overwritten. + @param[in, out] BufferSize For get-file-size operations, *BufferSize = returns the size of the + requested file. + @param[in] BlockSize The requested block size to be used during= a TFTP transfer. + @param[in] ServerIp The TFTP / MTFTP server IP address. + @param[in] Filename A Null-terminated ASCII string that specif= ies a directory name + or a file name. + @param[in] Info Pointer to the MTFTP information. + @param[in] DontUseBuffer Set to FALSE for normal TFTP and MTFTP rea= d file operation. + + @retval EFI_SUCCESS The TFTP/MTFTP operation was completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error du= ring this operation. + @retval EFI_BUFFER_TOO_SMALL The buffer is not large enough to complete= the read operation. + @retval EFI_ABORTED The callback function aborted the TFTP/MTF= TP operation. + @retval EFI_TIMEOUT The TFTP/MTFTP operation timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during t= he MTFTP session. + @retval EFI_TFTP_ERROR A TFTP error packet was received during th= e MTFTP session. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcMtftp ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation, + IN OUT VOID *BufferPtr OPTIONAL, + 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 + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_MTFTP4_CONFIG_DATA Mtftp4Config; + EFI_MTFTP6_CONFIG_DATA Mtftp6Config; + VOID *Config; + EFI_STATUS Status; + EFI_PXE_BASE_CODE_IP_FILTER IpFilter; + + + if ((This =3D=3D NULL) || + (Filename =3D=3D NULL) || + (BufferSize =3D=3D NULL) || + (ServerIp =3D=3D NULL) || + ((BufferPtr =3D=3D NULL) && DontUseBuffer) || + ((BlockSize !=3D NULL) && (*BlockSize < PXE_MTFTP_DEFAULT_BLOCK_SIZE= )) || + (!NetIp4IsUnicast (NTOHL (ServerIp->Addr[0]), 0) && !NetIp6IsValidUn= icast (&ServerIp->v6))) { + return EFI_INVALID_PARAMETER; + } + + Config =3D NULL; + Status =3D EFI_DEVICE_ERROR; + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + + if (Mode->UsingIpv6) { + // + // Set configuration data for Mtftp6 instance. + // + ZeroMem (&Mtftp6Config, sizeof (EFI_MTFTP6_CONFIG_DATA)); + Config =3D &Mtftp6Config; + Mtftp6Config.TimeoutValue =3D PXEBC_MTFTP_TIMEOUT; + Mtftp6Config.TryCount =3D PXEBC_MTFTP_RETRIES; + CopyMem (&Mtftp6Config.StationIp, &Private->StationIp.v6, sizeof (EFI_= IPv6_ADDRESS)); + CopyMem (&Mtftp6Config.ServerIp, &ServerIp->v6, sizeof (EFI_IPv6_ADDRE= SS)); + // + // Stop Udp6Read instance + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + } else { + // + // Set configuration data for Mtftp4 instance. + // + ZeroMem (&Mtftp4Config, sizeof (EFI_MTFTP4_CONFIG_DATA)); + Config =3D &Mtftp4Config; + Mtftp4Config.UseDefaultSetting =3D FALSE; + Mtftp4Config.TimeoutValue =3D PXEBC_MTFTP_TIMEOUT; + Mtftp4Config.TryCount =3D PXEBC_MTFTP_RETRIES; + CopyMem (&Mtftp4Config.StationIp, &Private->StationIp.v4, sizeof (EFI_= IPv4_ADDRESS)); + CopyMem (&Mtftp4Config.SubnetMask, &Private->SubnetMask.v4, sizeof (EF= I_IPv4_ADDRESS)); + CopyMem (&Mtftp4Config.GatewayIp, &Private->GatewayIp.v4, sizeof (EFI_= IPv4_ADDRESS)); + CopyMem (&Mtftp4Config.ServerIp, &ServerIp->v4, sizeof (EFI_IPv4_ADDRE= SS)); + // + // Stop Udp4Read instance + // + Private->Udp4Read->Configure (Private->Udp4Read, NULL); + } + + Mode->TftpErrorReceived =3D FALSE; + Mode->IcmpErrorReceived =3D FALSE; + + switch (Operation) { + + case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE: + // + // Send TFTP request to get file size. + // + Status =3D PxeBcTftpGetFileSize ( + Private, + Config, + Filename, + BlockSize, + BufferSize + ); + + break; + + case EFI_PXE_BASE_CODE_TFTP_READ_FILE: + // + // Send TFTP request to read file. + // + Status =3D PxeBcTftpReadFile ( + Private, + Config, + Filename, + BlockSize, + BufferPtr, + BufferSize, + DontUseBuffer + ); + + break; + + case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE: + // + // Send TFTP request to write file. + // + Status =3D PxeBcTftpWriteFile ( + Private, + Config, + Filename, + Overwrite, + BlockSize, + BufferPtr, + BufferSize + ); + + break; + + case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY: + // + // Send TFTP request to read directory. + // + Status =3D PxeBcTftpReadDirectory ( + Private, + Config, + Filename, + BlockSize, + BufferPtr, + BufferSize, + DontUseBuffer + ); + + break; + + case EFI_PXE_BASE_CODE_MTFTP_GET_FILE_SIZE: + case EFI_PXE_BASE_CODE_MTFTP_READ_FILE: + case EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY: + Status =3D EFI_UNSUPPORTED; + + break; + + default: + Status =3D EFI_INVALID_PARAMETER; + + break; + } + + if (Status =3D=3D EFI_ICMP_ERROR) { + Mode->IcmpErrorReceived =3D TRUE; + } + + // + // Reconfigure the UDP instance with the default configuration. + // + if (Mode->UsingIpv6) { + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData= ); + } else { + Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData= ); + } + // + // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with th= e IP + // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_I= P_FILTER_STATION_IP. + // + ZeroMem(&IpFilter, sizeof (EFI_PXE_BASE_CODE_IP_FILTER)); + IpFilter.Filters =3D EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP; + This->SetIpFilter (This, &IpFilter); + + return Status; +} + + +/** + Writes a UDP packet to the network interface. + + This function writes a UDP packet specified by the (optional HeaderPtr a= nd) + BufferPtr parameters to the network interface. The UDP header is automat= ically + built by this routine. It uses the parameters OpFlags, DestIp, DestPort,= GatewayIp, + SrcIp, and SrcPort to build this header. If the packet is successfully b= uilt and + transmitted through the network interface, then EFI_SUCCESS will be retu= rned. + If a timeout occurs during the transmission of the packet, then EFI_TIME= OUT will + be returned. If an ICMP error occurs during the transmission of the pack= et, then + the IcmpErrorReceived field is set to TRUE, the IcmpError field is fille= d in and + EFI_ICMP_ERROR will be returned. If the Callback Protocol does not retur= n + EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE, then EFI_ABORTED will be ret= urned. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] OpFlags The UDP operation flags. + @param[in] DestIp The destination IP address. + @param[in] DestPort The destination UDP port number. + @param[in] GatewayIp The gateway IP address. + @param[in] SrcIp The source IP address. + @param[in, out] SrcPort The source UDP port number. + @param[in] HeaderSize An optional field which may be set to the = length of a header + at HeaderPtr to be prefixed to the data at= BufferPtr. + @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a = header to be + prefixed to the data at BufferPtr. + @param[in] BufferSize A pointer to the size of the data at Buffe= rPtr. + @param[in] BufferPtr A pointer to the data to be written. + + @retval EFI_SUCCESS The UDP Write operation completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_BAD_BUFFER_SIZE The buffer is too long to be transmitted. + @retval EFI_ABORTED The callback function aborted the UDP Writ= e operation. + @retval EFI_TIMEOUT The UDP Write operation timed out. + @retval EFI_ICMP_ERROR An ICMP error packet was received during t= he UDP write session. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcUdpWrite ( + 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 + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_UDP4_SESSION_DATA Udp4Session; + EFI_UDP6_SESSION_DATA Udp6Session; + EFI_STATUS Status; + BOOLEAN DoNotFragment; + + if (This =3D=3D NULL || DestIp =3D=3D NULL || DestPort =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + + if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT) !=3D 0) { + DoNotFragment =3D FALSE; + } else { + DoNotFragment =3D TRUE; + } + + if (!Mode->UsingIpv6 && GatewayIp !=3D NULL && !NetIp4IsUnicast (NTOHL (= GatewayIp->Addr[0]), 0)) { + // + // Gateway is provided but it's not a unicast IPv4 address, while it w= ill be ignored for IPv6. + // + return EFI_INVALID_PARAMETER; + } + + if (HeaderSize !=3D NULL && (*HeaderSize =3D=3D 0 || HeaderPtr =3D=3D NU= LL)) { + return EFI_INVALID_PARAMETER; + } + + if (BufferSize =3D=3D NULL || (*BufferSize !=3D 0 && BufferPtr =3D=3D NU= LL)) { + return EFI_INVALID_PARAMETER; + } + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + if (!Private->IsAddressOk && SrcIp =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Private->CurSrcPort =3D=3D 0 || + (SrcPort !=3D NULL && *SrcPort !=3D Private->CurSrcPort)) { + // + // Reconfigure UDPv4/UDPv6 for UdpWrite if the source port changed. + // + if (SrcPort !=3D NULL) { + Private->CurSrcPort =3D *SrcPort; + } + } + + if (Mode->UsingIpv6) { + Status =3D PxeBcConfigUdp6Write ( + Private->Udp6Write, + &Private->StationIp.v6, + &Private->CurSrcPort + ); + } else { + // + // Configure the UDPv4 instance with gateway information from DHCP ser= ver as default. + // + Status =3D PxeBcConfigUdp4Write ( + Private->Udp4Write, + &Private->StationIp.v4, + &Private->SubnetMask.v4, + &Private->GatewayIp.v4, + &Private->CurSrcPort, + DoNotFragment + ); + } + + if (EFI_ERROR (Status)) { + Private->CurSrcPort =3D 0; + return EFI_INVALID_PARAMETER; + } else if (SrcPort !=3D NULL) { + *SrcPort =3D Private->CurSrcPort; + } + + // + // Start a timer as timeout event for this blocking API. + // + gBS->SetTimer (Private->UdpTimeOutEvent, TimerRelative, PXEBC_UDP_TIMEOU= T); + + if (Mode->UsingIpv6) { + // + // Construct UDPv6 session data. + // + ZeroMem (&Udp6Session, sizeof (EFI_UDP6_SESSION_DATA)); + CopyMem (&Udp6Session.DestinationAddress, DestIp, sizeof (EFI_IPv6_ADD= RESS)); + Udp6Session.DestinationPort =3D *DestPort; + if (SrcIp !=3D NULL) { + CopyMem (&Udp6Session.SourceAddress, SrcIp, sizeof (EFI_IPv6_ADDRESS= )); + } + if (SrcPort !=3D NULL) { + Udp6Session.SourcePort =3D *SrcPort; + } + + Status =3D PxeBcUdp6Write ( + Private->Udp6Write, + &Udp6Session, + Private->UdpTimeOutEvent, + HeaderSize, + HeaderPtr, + BufferSize, + BufferPtr + ); + } else { + // + // Construct UDPv4 session data. + // + ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA)); + CopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADD= RESS)); + Udp4Session.DestinationPort =3D *DestPort; + if (SrcIp !=3D NULL) { + CopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS= )); + } + if (SrcPort !=3D NULL) { + Udp4Session.SourcePort =3D *SrcPort; + } + // + // Override the gateway information if user specified. + // + Status =3D PxeBcUdp4Write ( + Private->Udp4Write, + &Udp4Session, + Private->UdpTimeOutEvent, + (EFI_IPv4_ADDRESS *) GatewayIp, + HeaderSize, + HeaderPtr, + BufferSize, + BufferPtr + ); + } + + gBS->SetTimer (Private->UdpTimeOutEvent, TimerCancel, 0); + + + // + // Reset the UdpWrite instance. + // + if (Mode->UsingIpv6) { + Private->Udp6Write->Configure (Private->Udp6Write, NULL); + } else { + Private->Udp4Write->Configure (Private->Udp4Write, NULL); + } + + return Status; +} + + +/** + Reads a UDP packet from the network interface. ++ + This function reads a UDP packet from a network interface. The data cont= ents + are returned in (the optional HeaderPtr and) BufferPtr, and the size of = the + buffer received is returned in BufferSize . If the input BufferSize is s= maller + than the UDP packet received (less optional HeaderSize), it will be set = to the + required size, and EFI_BUFFER_TOO_SMALL will be returned. In this case, = the + contents of BufferPtr are undefined, and the packet is lost. If a UDP pa= cket is + successfully received, then EFI_SUCCESS will be returned, and the inform= ation + from the UDP header will be returned in DestIp, DestPort, SrcIp, and Src= Port if + they are not NULL. Depending on the values of OpFlags and the DestIp, De= stPort, + SrcIp, and SrcPort input values, different types of UDP packet receive f= iltering + will be performed. The following tables summarize these receive filter o= perations. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] OpFlags The UDP operation flags. + @param[in, out] DestIp The destination IP address. + @param[in, out] DestPort The destination UDP port number. + @param[in, out] SrcIp The source IP address. + @param[in, out] SrcPort The source UDP port number. + @param[in] HeaderSize An optional field which may be set to the = length of a + header at HeaderPtr to be prefixed to the = data at BufferPtr. + @param[in] HeaderPtr If HeaderSize is not NULL, a pointer to a = header to be + prefixed to the data at BufferPtr. + @param[in, out] BufferSize A pointer to the size of the data at Buffe= rPtr. + @param[in] BufferPtr A pointer to the data to be read. + + @retval EFI_SUCCESS The UDP Read operation was completed. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error du= ring this operation. + @retval EFI_BUFFER_TOO_SMALL The packet is larger than Buffer can hold. + @retval EFI_ABORTED The callback function aborted the UDP Read= operation. + @retval EFI_TIMEOUT The UDP Read operation timed out. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcUdpRead ( + 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 + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_UDP4_COMPLETION_TOKEN Udp4Token; + EFI_UDP6_COMPLETION_TOKEN Udp6Token; + EFI_UDP4_RECEIVE_DATA *Udp4Rx; + EFI_UDP6_RECEIVE_DATA *Udp6Rx; + EFI_STATUS Status; + BOOLEAN IsDone; + BOOLEAN IsMatched; + UINTN CopiedLen; + UINTN HeaderLen; + UINTN HeaderCopiedLen; + UINTN BufferCopiedLen; + UINT32 FragmentLength; + UINTN FragmentIndex; + UINT8 *FragmentBuffer; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + IsDone =3D FALSE; + IsMatched =3D FALSE; + Udp4Rx =3D NULL; + Udp6Rx =3D NULL; + + if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) =3D=3D 0 &&= DestPort =3D=3D NULL) || + ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) =3D=3D 0 && Sr= cIp =3D=3D NULL) || + ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) =3D=3D 0 && = SrcPort =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((HeaderSize !=3D NULL && *HeaderSize =3D=3D 0) || (HeaderSize !=3D N= ULL && HeaderPtr =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if ((BufferSize =3D=3D NULL) || (BufferPtr =3D=3D NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + ZeroMem (&Udp6Token, sizeof (EFI_UDP6_COMPLETION_TOKEN)); + ZeroMem (&Udp4Token, sizeof (EFI_UDP4_COMPLETION_TOKEN)); + + if (Mode->UsingIpv6) { + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &IsDone, + &Udp6Token.Event + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + } else { + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &IsDone, + &Udp4Token.Event + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + } + + // + // Start a timer as timeout event for this blocking API. + // + gBS->SetTimer (Private->UdpTimeOutEvent, TimerRelative, PXEBC_UDP_TIMEOU= T); + Mode->IcmpErrorReceived =3D FALSE; + + // + // Read packet by Udp4Read/Udp6Read until matched or timeout. + // + while (!IsMatched && !EFI_ERROR (Status)) { + if (Mode->UsingIpv6) { + Status =3D PxeBcUdp6Read ( + Private->Udp6Read, + &Udp6Token, + Mode, + Private->UdpTimeOutEvent, + OpFlags, + &IsDone, + &IsMatched, + DestIp, + DestPort, + SrcIp, + SrcPort + ); + } else { + Status =3D PxeBcUdp4Read ( + Private->Udp4Read, + &Udp4Token, + Mode, + Private->UdpTimeOutEvent, + OpFlags, + &IsDone, + &IsMatched, + DestIp, + DestPort, + SrcIp, + SrcPort + ); + } + } + + if (Status =3D=3D EFI_ICMP_ERROR || + Status =3D=3D EFI_NETWORK_UNREACHABLE || + Status =3D=3D EFI_HOST_UNREACHABLE || + Status =3D=3D EFI_PROTOCOL_UNREACHABLE || + Status =3D=3D EFI_PORT_UNREACHABLE) { + // + // Get different return status for icmp error from Udp, refers to UEFI= spec. + // + Mode->IcmpErrorReceived =3D TRUE; + } + gBS->SetTimer (Private->UdpTimeOutEvent, TimerCancel, 0); + + if (IsMatched) { + // + // Copy the rececived packet to user if matched by filter. + // + if (Mode->UsingIpv6) { + Udp6Rx =3D Udp6Token.Packet.RxData; + ASSERT (Udp6Rx !=3D NULL); + + HeaderLen =3D 0; + if (HeaderSize !=3D NULL) { + HeaderLen =3D MIN (*HeaderSize, Udp6Rx->DataLength); + } + + if (Udp6Rx->DataLength - HeaderLen > *BufferSize) { + Status =3D EFI_BUFFER_TOO_SMALL; + } else { + if (HeaderSize !=3D NULL) { + *HeaderSize =3D HeaderLen; + } + *BufferSize =3D Udp6Rx->DataLength - HeaderLen; + + HeaderCopiedLen =3D 0; + BufferCopiedLen =3D 0; + for (FragmentIndex =3D 0; FragmentIndex < Udp6Rx->FragmentCount; F= ragmentIndex++) { + FragmentLength =3D Udp6Rx->FragmentTable[FragmentIndex].Fragment= Length; + FragmentBuffer =3D Udp6Rx->FragmentTable[FragmentIndex].Fragment= Buffer; + if (HeaderCopiedLen + FragmentLength < HeaderLen) { + // + // Copy the header part of received data. + // + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer= , FragmentLength); + HeaderCopiedLen +=3D FragmentLength; + } else if (HeaderCopiedLen < HeaderLen) { + // + // Copy the header part of received data. + // + CopiedLen =3D HeaderLen - HeaderCopiedLen; + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer= , CopiedLen); + HeaderCopiedLen +=3D CopiedLen; + + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer= + CopiedLen, FragmentLength - CopiedLen); + BufferCopiedLen +=3D (FragmentLength - CopiedLen); + } else { + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer= , FragmentLength); + BufferCopiedLen +=3D FragmentLength; + } + } + } + // + // Recycle the receiving buffer after copy to user. + // + gBS->SignalEvent (Udp6Rx->RecycleSignal); + } else { + Udp4Rx =3D Udp4Token.Packet.RxData; + ASSERT (Udp4Rx !=3D NULL); + + HeaderLen =3D 0; + if (HeaderSize !=3D NULL) { + HeaderLen =3D MIN (*HeaderSize, Udp4Rx->DataLength); + } + + if (Udp4Rx->DataLength - HeaderLen > *BufferSize) { + Status =3D EFI_BUFFER_TOO_SMALL; + } else { + if (HeaderSize !=3D NULL) { + *HeaderSize =3D HeaderLen; + } + *BufferSize =3D Udp4Rx->DataLength - HeaderLen; + + HeaderCopiedLen =3D 0; + BufferCopiedLen =3D 0; + for (FragmentIndex =3D 0; FragmentIndex < Udp4Rx->FragmentCount; F= ragmentIndex++) { + FragmentLength =3D Udp4Rx->FragmentTable[FragmentIndex].Fragment= Length; + FragmentBuffer =3D Udp4Rx->FragmentTable[FragmentIndex].Fragment= Buffer; + if (HeaderCopiedLen + FragmentLength < HeaderLen) { + // + // Copy the header part of received data. + // + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer= , FragmentLength); + HeaderCopiedLen +=3D FragmentLength; + } else if (HeaderCopiedLen < HeaderLen) { + // + // Copy the header part of received data. + // + CopiedLen =3D HeaderLen - HeaderCopiedLen; + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer= , CopiedLen); + HeaderCopiedLen +=3D CopiedLen; + + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer= + CopiedLen, FragmentLength - CopiedLen); + BufferCopiedLen +=3D (FragmentLength - CopiedLen); + } else { + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer= , FragmentLength); + BufferCopiedLen +=3D FragmentLength; + } + } + } + // + // Recycle the receiving buffer after copy to user. + // + gBS->SignalEvent (Udp4Rx->RecycleSignal); + } + } + + if (Mode->UsingIpv6) { + Private->Udp6Read->Cancel (Private->Udp6Read, &Udp6Token); + gBS->CloseEvent (Udp6Token.Event); + } else { + Private->Udp4Read->Cancel (Private->Udp4Read, &Udp4Token); + gBS->CloseEvent (Udp4Token.Event); + } + + return Status; +} + + +/** + Updates the IP receive filters of a network device and enables software = filtering. + + The NewFilter field is used to modify the network device's current IP re= ceive + filter settings and to enable a software filter. This function updates t= he IpFilter + field of the EFI_PXE_BASE_CODE_MODE structure with the contents of NewIp= Filter. + The software filter is used when the USE_FILTER in OpFlags is set to Udp= Read(). + The current hardware filter remains in effect no matter what the setting= s of OpFlags. + This is so that the meaning of ANY_DEST_IP set in OpFlags to UdpRead() i= s from those + packets whose reception is enabled in hardware-physical NIC address (uni= cast), + broadcast address, logical address or addresses (multicast), or all (pro= miscuous). + UdpRead() does not modify the IP filter settings. + Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the I= P receive + filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_ST= ATION_IP. + If an application or driver wishes to preserve the IP receive filter set= tings, + it will have to preserve the IP receive filter settings before these cal= ls, and + use SetIpFilter() to restore them after the calls. If incompatible filte= ring is + requested (for example, PROMISCUOUS with anything else), or if the devic= e does not + support a requested filter setting and it cannot be accommodated in soft= ware + (for example, PROMISCUOUS not supported), EFI_INVALID_PARAMETER will be = returned. + The IPlist field is used to enable IPs other than the StationIP. They ma= y be + multicast or unicast. If IPcnt is set as well as EFI_PXE_BASE_CODE_IP_FI= LTER_STATION_IP, + then both the StationIP and the IPs from the IPlist will be used. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] NewFilter Pointer to the new set of IP receive filte= rs. + + @retval EFI_SUCCESS The IP receive filter settings were update= d. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcSetIpFilter ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter + ) +{ + EFI_STATUS Status; + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_UDP4_CONFIG_DATA *Udp4Cfg; + EFI_UDP6_CONFIG_DATA *Udp6Cfg; + UINTN Index; + BOOLEAN NeedPromiscuous; + BOOLEAN AcceptPromiscuous; + BOOLEAN AcceptBroadcast; + BOOLEAN MultiCastUpdate; + + if (This =3D=3D NULL || NewFilter =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + Status =3D EFI_SUCCESS; + NeedPromiscuous =3D FALSE; + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + for (Index =3D 0; Index < NewFilter->IpCnt; Index++) { + ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT); + if (!Mode->UsingIpv6 && + IP4_IS_LOCAL_BROADCAST (EFI_IP4 (NewFilter->IpList[Index].v4))) { + // + // IPv4 broadcast address should not be in IP filter. + // + return EFI_INVALID_PARAMETER; + } + if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) !=3D= 0 && + (NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), 0) || + NetIp6IsValidUnicast (&NewFilter->IpList[Index].v6))) { + // + // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IPv4/IPv6 ad= dress + // is in IpList, promiscuous mode is needed. + // + NeedPromiscuous =3D TRUE; + } + } + + AcceptPromiscuous =3D FALSE; + AcceptBroadcast =3D FALSE; + MultiCastUpdate =3D FALSE; + + if (NeedPromiscuous || + (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) !=3D = 0 || + (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTIC= AST) !=3D 0) { + // + // Configure UDPv4/UDPv6 as promiscuous mode to receive all packets. + // + AcceptPromiscuous =3D TRUE; + } else if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) = !=3D 0) { + // + // Configure UDPv4 to receive all broadcast packets. + // + AcceptBroadcast =3D TRUE; + } + + // + // In multicast condition when Promiscuous FALSE and IpCnt no-zero. + // Here check if there is any update of the multicast ip address. If yes= , + // we need leave the old multicast group (by Config UDP instance to NULL= ), + // and join the new multicast group. + // + if (!AcceptPromiscuous) { + if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) !=3D= 0) { + if (Mode->IpFilter.IpCnt !=3D NewFilter->IpCnt) { + MultiCastUpdate =3D TRUE; + } else if (CompareMem (Mode->IpFilter.IpList, NewFilter->IpList, New= Filter->IpCnt * sizeof (EFI_IP_ADDRESS)) !=3D 0 ) { + MultiCastUpdate =3D TRUE; + } + } + } + + if (!Mode->UsingIpv6) { + // + // Check whether we need reconfigure the UDP4 instance. + // + Udp4Cfg =3D &Private->Udp4CfgData; + if ((AcceptPromiscuous !=3D Udp4Cfg->AcceptPromiscuous) || + (AcceptBroadcast !=3D Udp4Cfg->AcceptBroadcast) || MultiCastUpd= ate) { + // + // Clear the UDP4 instance configuration, all joined groups will be = left + // during the operation. + // + Private->Udp4Read->Configure (Private->Udp4Read, NULL); + =20 + // + // Configure the UDP instance with the new configuration. + // + Udp4Cfg->AcceptPromiscuous =3D AcceptPromiscuous; + Udp4Cfg->AcceptBroadcast =3D AcceptBroadcast; + Status =3D Private->Udp4Read->Configure (Private->Udp4Read, Udp4Cfg)= ; + if (EFI_ERROR (Status)) { + return Status; + } + =20 + // + // In not Promiscuous mode, need to join the new multicast group. + // + if (!AcceptPromiscuous) { + for (Index =3D 0; Index < NewFilter->IpCnt; ++Index) { + if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) = { + // + // Join the mutilcast group. + // + Status =3D Private->Udp4Read->Groups (Private->Udp4Read, TRUE,= &NewFilter->IpList[Index].v4); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + } + } + } else { + // + // Check whether we need reconfigure the UDP6 instance. + // + Udp6Cfg =3D &Private->Udp6CfgData; + if ((AcceptPromiscuous !=3D Udp6Cfg->AcceptPromiscuous) || MultiCastUp= date) { + // + // Clear the UDP6 instance configuration, all joined groups will be = left + // during the operation. + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + =20 + // + // Configure the UDP instance with the new configuration. + // + Udp6Cfg->AcceptPromiscuous =3D AcceptPromiscuous; + Status =3D Private->Udp6Read->Configure (Private->Udp6Read, Udp6Cfg)= ; + if (EFI_ERROR (Status)) { + return Status; + } + =20 + // + // In not Promiscuous mode, need to join the new multicast group. + // + if (!AcceptPromiscuous) { + for (Index =3D 0; Index < NewFilter->IpCnt; ++Index) { + if (IP6_IS_MULTICAST (&NewFilter->IpList[Index].v6)) { + // + // Join the mutilcast group. + // + Status =3D Private->Udp6Read->Groups (Private->Udp6Read, TRUE,= &NewFilter->IpList[Index].v6); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + } + } + } + + // + // Save the new IP filter into mode data. + // + CopyMem (&Mode->IpFilter, NewFilter, sizeof (Mode->IpFilter)); + + return Status; +} + + +/** + Uses the ARP protocol to resolve a MAC address. It is not supported for = IPv6. + + This function uses the ARP protocol to resolve a MAC address. The IP add= ress specified + by IpAddr is used to resolve a MAC address. If the ARP protocol succeeds= in resolving + the specified address, then the ArpCacheEntries and ArpCache fields of t= he mode data + are updated, and EFI_SUCCESS is returned. If MacAddr is not NULL, the re= solved + MAC address is placed there as well. If the PXE Base Code protocol is i= n the + stopped state, then EFI_NOT_STARTED is returned. If the ARP protocol enc= ounters + a timeout condition while attempting to resolve an address, then EFI_TIM= EOUT is + returned. If the Callback Protocol does not return EFI_PXE_BASE_CODE_CAL= LBACK_STATUS_CONTINUE, + then EFI_ABORTED is returned. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] IpAddr Pointer to the IP address that is used to = resolve a MAC address. + @param[in] MacAddr If not NULL, a pointer to the MAC address = that was resolved with the + ARP protocol. + + @retval EFI_SUCCESS The IP or MAC address was resolved. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + @retval EFI_DEVICE_ERROR The network device encountered an error du= ring this operation. + @retval EFI_ICMP_ERROR An error occur with the ICMP packet messag= e. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcArp ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_IP_ADDRESS *IpAddr, + IN EFI_MAC_ADDRESS *MacAddr OPTIONAL + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_EVENT ResolvedEvent; + EFI_STATUS Status; + EFI_MAC_ADDRESS TempMac; + EFI_MAC_ADDRESS ZeroMac; + BOOLEAN IsResolved; + + if (This =3D=3D NULL || IpAddr =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + ResolvedEvent =3D NULL; + Status =3D EFI_SUCCESS; + IsResolved =3D FALSE; + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + if (Mode->UsingIpv6) { + return EFI_UNSUPPORTED; + } + + // + // Station address should be ready before do arp. + // + if (!Private->IsAddressOk) { + return EFI_INVALID_PARAMETER; + } + + Mode->IcmpErrorReceived =3D FALSE; + ZeroMem (&TempMac, sizeof (EFI_MAC_ADDRESS)); + ZeroMem (&ZeroMac, sizeof (EFI_MAC_ADDRESS)); + + if (!Mode->AutoArp) { + // + // If AutoArp is FALSE, only search in the current Arp cache. + // + PxeBcArpCacheUpdate (NULL, Private); + if (!PxeBcCheckArpCache (Mode, &IpAddr->v4, &TempMac)) { + Status =3D EFI_DEVICE_ERROR; + goto ON_EXIT; + } + } else { + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &IsResolved, + &ResolvedEvent + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // If AutoArp is TRUE, try to send Arp request on initiative. + // + Status =3D Private->Arp->Request (Private->Arp, &IpAddr->v4, ResolvedE= vent, &TempMac); + if (EFI_ERROR (Status) && Status !=3D EFI_NOT_READY) { + goto ON_EXIT; + } + + while (!IsResolved) { + if (CompareMem (&TempMac, &ZeroMac, sizeof (EFI_MAC_ADDRESS)) !=3D 0= ) { + break; + } + } + if (CompareMem (&TempMac, &ZeroMac, sizeof (EFI_MAC_ADDRESS)) !=3D 0) = { + Status =3D EFI_SUCCESS; + } else { + Status =3D EFI_TIMEOUT; + } + } + + // + // Copy the Mac address to user if needed. + // + if (MacAddr !=3D NULL && !EFI_ERROR (Status)) { + CopyMem (MacAddr, &TempMac, sizeof (EFI_MAC_ADDRESS)); + } + +ON_EXIT: + if (ResolvedEvent !=3D NULL) { + gBS->CloseEvent (ResolvedEvent); + } + return Status; +} + + +/** + Updates the parameters that affect the operation of the PXE Base Code Pr= otocol. + + This function sets parameters that affect the operation of the PXE Base = Code Protocol. + The parameter specified by NewAutoArp is used to control the generation = of ARP + protocol packets. If NewAutoArp is TRUE, then ARP Protocol packets will = be generated + as required by the PXE Base Code Protocol. If NewAutoArp is FALSE, then = no ARP + Protocol packets will be generated. In this case, the only mappings that= are + available are those stored in the ArpCache of the EFI_PXE_BASE_CODE_MODE= structure. + If there are not enough mappings in the ArpCache to perform a PXE Base C= ode Protocol + service, then the service will fail. This function updates the AutoArp f= ield of + the EFI_PXE_BASE_CODE_MODE structure to NewAutoArp. + The SetParameters() call must be invoked after a Callback Protocol is in= stalled + to enable the use of callbacks. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] NewAutoArp If not NULL, a pointer to a value that spe= cifies whether to replace the + current value of AutoARP. + @param[in] NewSendGUID If not NULL, a pointer to a value that spe= cifies whether to replace the + current value of SendGUID. + @param[in] NewTTL If not NULL, a pointer to be used in place= of the current value of TTL, + the "time to live" field of the IP header. + @param[in] NewToS If not NULL, a pointer to be used in place= of the current value of ToS, + the "type of service" field of the IP head= er. + @param[in] NewMakeCallback If not NULL, a pointer to a value that spe= cifies whether to replace the + current value of the MakeCallback field of= the Mode structure. + + @retval EFI_SUCCESS The new parameters values were updated. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcSetParameters ( + 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 + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_GUID SystemGuid; + EFI_STATUS Status; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + if (NewMakeCallback !=3D NULL) { + if (*NewMakeCallback) { + // + // Update the previous PxeBcCallback protocol. + // + Status =3D gBS->HandleProtocol ( + Private->Controller, + &gEfiPxeBaseCodeCallbackProtocolGuid, + (VOID **) &Private->PxeBcCallback + ); + + if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback =3D=3D N= ULL)) { + return EFI_INVALID_PARAMETER; + } + } else { + Private->PxeBcCallback =3D NULL; + } + Mode->MakeCallbacks =3D *NewMakeCallback; + } + + if (NewSendGUID !=3D NULL) { + if (*NewSendGUID && EFI_ERROR (NetLibGetSystemGuid (&SystemGuid))) { + return EFI_INVALID_PARAMETER; + } + Mode->SendGUID =3D *NewSendGUID; + } + + if (NewAutoArp !=3D NULL) { + Mode->AutoArp =3D *NewAutoArp; + } + + if (NewTTL !=3D NULL) { + Mode->TTL =3D *NewTTL; + } + + if (NewToS !=3D NULL) { + Mode->ToS =3D *NewToS; + } + + return EFI_SUCCESS; +} + + +/** + Updates the station IP address and/or subnet mask values of a network de= vice. + + This function updates the station IP address and/or subnet mask values o= f a network + device. The NewStationIp field is used to modify the network device's cu= rrent IP address. + If NewStationIP is NULL, then the current IP address will not be modifie= d. Otherwise, + this function updates the StationIp field of the EFI_PXE_BASE_CODE_MODE = structure + with NewStationIp. The NewSubnetMask field is used to modify the network= device's current subnet + mask. If NewSubnetMask is NULL, then the current subnet mask will not be= modified. + Otherwise, this function updates the SubnetMask field of the EFI_PXE_BAS= E_CODE_MODE + structure with NewSubnetMask. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROTOCOL = instance. + @param[in] NewStationIp Pointer to the new IP address to be used b= y the network device. + @param[in] NewSubnetMask Pointer to the new subnet mask to be used = by the network device. + + @retval EFI_SUCCESS The new station IP address and/or subnet m= ask were updated. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stopp= ed state. + @retval EFI_INVALID_PARAMETER One or more parameters are invalid. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcSetStationIP ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN EFI_IP_ADDRESS *NewStationIp OPTIONAL, + IN EFI_IP_ADDRESS *NewSubnetMask OPTIONAL + ) +{ + EFI_STATUS Status; + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_ARP_CONFIG_DATA ArpConfigData; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (NewStationIp !=3D NULL && + (!NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0) && + !NetIp6IsValidUnicast (&NewStationIp->v6))) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + Status =3D EFI_SUCCESS; + + if (!Mode->UsingIpv6 && + NewSubnetMask !=3D NULL && + !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) { + return EFI_INVALID_PARAMETER; + } + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + if (Mode->UsingIpv6 && NewStationIp !=3D NULL) { + // + // Set the IPv6 address by Ip6Config protocol. + // + Status =3D PxeBcRegisterIp6Address (Private, &NewStationIp->v6); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + } else if (!Mode->UsingIpv6 && NewStationIp !=3D NULL) { + // + // Configure the corresponding ARP with the IPv4 address. + // + ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA)); + + ArpConfigData.SwAddressType =3D 0x0800; + ArpConfigData.SwAddressLength =3D (UINT8) sizeof (EFI_IPv4_ADDRESS); + ArpConfigData.StationAddress =3D &NewStationIp->v4; + + Private->Arp->Configure (Private->Arp, NULL); + Private->Arp->Configure (Private->Arp, &ArpConfigData); + + if (NewSubnetMask !=3D NULL) { + Mode->RouteTableEntries =3D 1; + Mode->RouteTable[0].IpAddr.Addr[0] =3D NewStationIp->Addr[0] & N= ewSubnetMask->Addr[0]; + Mode->RouteTable[0].SubnetMask.Addr[0] =3D NewSubnetMask->Addr[0]; + Mode->RouteTable[0].GwAddr.Addr[0] =3D 0; + } + + Private->IsAddressOk =3D TRUE; + } + + if (NewStationIp !=3D NULL) { + CopyMem (&Mode->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&Private->StationIp, NewStationIp, sizeof (EFI_IP_ADDRESS)); + } + + if (!Mode->UsingIpv6 && NewSubnetMask !=3D NULL) { + CopyMem (&Mode->SubnetMask, NewSubnetMask, sizeof (EFI_IP_ADDRESS)); + CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS))= ; + } + + Status =3D PxeBcFlushStationIp (Private, NewStationIp, NewSubnetMask); +ON_EXIT: + return Status; +} + + +/** + Updates the contents of the cached DHCP and Discover packets. + + The pointers to the new packets are used to update the contents of the c= ached + packets in the EFI_PXE_BASE_CODE_MODE structure. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_PROT= OCOL instance. + @param[in] NewDhcpDiscoverValid Pointer to a value that will replace = the current + DhcpDiscoverValid field. + @param[in] NewDhcpAckReceived Pointer to a value that will replace = the current + DhcpAckReceived field. + @param[in] NewProxyOfferReceived Pointer to a value that will replace = the current + ProxyOfferReceived field. + @param[in] NewPxeDiscoverValid Pointer to a value that will replace = the current + ProxyOfferReceived field. + @param[in] NewPxeReplyReceived Pointer to a value that will replace = the current + PxeReplyReceived field. + @param[in] NewPxeBisReplyReceived Pointer to a value that will replace = the current + PxeBisReplyReceived field. + @param[in] NewDhcpDiscover Pointer to the new cached DHCP Discov= er packet contents. + @param[in] NewDhcpAck Pointer to the new cached DHCP Ack pa= cket contents. + @param[in] NewProxyOffer Pointer to the new cached Proxy Offer= packet contents. + @param[in] NewPxeDiscover Pointer to the new cached PXE Discove= r packet contents. + @param[in] NewPxeReply Pointer to the new cached PXE Reply p= acket contents. + @param[in] NewPxeBisReply Pointer to the new cached PXE BIS Rep= ly packet contents. + + @retval EFI_SUCCESS The cached packet contents were updated. + @retval EFI_NOT_STARTED The PXE Base Code Protocol is in the stop= ped state. + @retval EFI_INVALID_PARAMETER This is NULL or does not point to a valid + EFI_PXE_BASE_CODE_PROTOCOL structure. + +**/ +EFI_STATUS +EFIAPI +EfiPxeBcSetPackets ( + IN EFI_PXE_BASE_CODE_PROTOCOL *This, + IN BOOLEAN *NewDhcpDiscoverValid OPTIONAL, + IN BOOLEAN *NewDhcpAckReceived OPTIONAL, + IN BOOLEAN *NewProxyOfferReceived OPTIONAL, + IN BOOLEAN *NewPxeDiscoverValid OPTIONAL, + IN BOOLEAN *NewPxeReplyReceived OPTIONAL, + IN 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 + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + + if (This =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Private =3D PXEBC_PRIVATE_DATA_FROM_PXEBC (This); + Mode =3D Private->PxeBc.Mode; + + if (!Mode->Started) { + return EFI_NOT_STARTED; + } + + if (NewDhcpDiscoverValid !=3D NULL) { + Mode->DhcpDiscoverValid =3D *NewDhcpDiscoverValid; + } + + if (NewDhcpAckReceived !=3D NULL) { + Mode->DhcpAckReceived =3D *NewDhcpAckReceived; + } + + if (NewProxyOfferReceived !=3D NULL) { + Mode->ProxyOfferReceived =3D *NewProxyOfferReceived; + } + + if (NewPxeDiscoverValid !=3D NULL) { + Mode->PxeDiscoverValid =3D *NewPxeDiscoverValid; + } + + if (NewPxeReplyReceived !=3D NULL) { + Mode->PxeReplyReceived =3D *NewPxeReplyReceived; + } + + if (NewPxeBisReplyReceived !=3D NULL) { + Mode->PxeBisReplyReceived =3D *NewPxeBisReplyReceived; + } + + if (NewDhcpDiscover !=3D NULL) { + CopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CO= DE_PACKET)); + } + + if (NewDhcpAck !=3D NULL) { + CopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET)= ); + } + + if (NewProxyOffer !=3D NULL) { + CopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_P= ACKET)); + } + + if (NewPxeDiscover !=3D NULL) { + CopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE= _PACKET)); + } + + if (NewPxeReply !=3D NULL) { + CopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKE= T)); + } + + if (NewPxeBisReply !=3D NULL) { + CopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE= _PACKET)); + } + + return EFI_SUCCESS; +} + +EFI_PXE_BASE_CODE_PROTOCOL gPxeBcProtocolTemplate =3D { + EFI_PXE_BASE_CODE_PROTOCOL_REVISION, + EfiPxeBcStart, + EfiPxeBcStop, + EfiPxeBcDhcp, + EfiPxeBcDiscover, + EfiPxeBcMtftp, + EfiPxeBcUdpWrite, + EfiPxeBcUdpRead, + EfiPxeBcSetIpFilter, + EfiPxeBcArp, + EfiPxeBcSetParameters, + EfiPxeBcSetStationIP, + EfiPxeBcSetPackets, + NULL +}; + + +/** + Callback function that is invoked when the PXE Base Code Protocol is abo= ut to transmit, has + received, or is waiting to receive a packet. + + This function is invoked when the PXE Base Code Protocol is about to tra= nsmit, has received, + or is waiting to receive a packet. Parameters Function and Received spec= ify the type of event. + Parameters PacketLen and Packet specify the packet that generated the ev= ent. If these fields + are zero and NULL respectively, then this is a status update callback. I= f the operation specified + by Function is to continue, then CALLBACK_STATUS_CONTINUE should be retu= rned. If the operation + specified by Function should be aborted, then CALLBACK_STATUS_ABORT shou= ld be returned. Due to + the polling nature of UEFI device drivers, a callback function should no= t execute for more than 5 ms. + The SetParameters() function must be called after a Callback Protocol is= installed to enable the + use of callbacks. + + @param[in] This Pointer to the EFI_PXE_BASE_CODE_CALLBACK_= PROTOCOL instance. + @param[in] Function The PXE Base Code Protocol function that i= s waiting for an event. + @param[in] Received TRUE if the callback is being invoked due = to a receive event. FALSE if + the callback is being invoked due to a tra= nsmit event. + @param[in] PacketLength The length, in bytes, of Packet. This fiel= d will have a value of zero if + this is a wait for receive event. + @param[in] PacketPtr If Received is TRUE, a pointer to the pack= et that was just received; + otherwise a pointer to the packet that is = about to be transmitted. + + @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE If Function specifies= a continue operation. + @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT If Function specifies= an abort operation. + +**/ +EFI_PXE_BASE_CODE_CALLBACK_STATUS +EFIAPI +EfiPxeLoadFileCallback ( + 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 + ) +{ + EFI_INPUT_KEY Key; + EFI_STATUS Status; + + // + // Catch Ctrl-C or ESC to abort. + // + Status =3D gST->ConIn->ReadKeyStroke (gST->ConIn, &Key); + + if (!EFI_ERROR (Status)) { + + if (Key.ScanCode =3D=3D SCAN_ESC || Key.UnicodeChar =3D=3D (0x1F & 'c'= )) { + + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT; + } + } + // + // No print if receive packet + // + if (Received) { + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE; + } + // + // Print only for three functions + // + switch (Function) { + + case EFI_PXE_BASE_CODE_FUNCTION_MTFTP: + // + // Print only for open MTFTP packets, not every MTFTP packets + // + if (PacketLength !=3D 0 && PacketPtr !=3D NULL) { + if (PacketPtr->Raw[0x1C] !=3D 0x00 || PacketPtr->Raw[0x1D] !=3D 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; + } + + if (PacketLength !=3D 0 && PacketPtr !=3D NULL) { + // + // Print '.' when transmit a packet + // + AsciiPrint ("."); + } + + return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE; +} + +EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL gPxeBcCallBackTemplate =3D { + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION, + EfiPxeLoadFileCallback +}; + + +/** + Causes the driver to load a specified file. + + @param[in] This Protocol instance pointer. + @param[in] FilePath The device specific path of the file= to load. + @param[in] BootPolicy If TRUE, indicates that the request = originates from the + boot manager is attempting to load F= ilePath as a boot + selection. If FALSE, then FilePath m= ust match an exact file + to be loaded. + @param[in, out] BufferSize On input the size of Buffer in bytes= . On output with a return + code of EFI_SUCCESS, the amount of d= ata transferred to + Buffer. On output with a return code= of EFI_BUFFER_TOO_SMALL, + the size of Buffer required to retri= eve the requested file. + @param[in] Buffer The memory buffer to transfer the fi= le to. IF Buffer is NULL, + then no the size of the requested fi= le is returned in + BufferSize. + + @retval EFI_SUCCESS The file was loaded. + @retval EFI_UNSUPPORTED The device does not support the prov= ided BootPolicy. + @retval EFI_INVALID_PARAMETER FilePath is not a valid device path,= or + BufferSize is NULL. + @retval EFI_NO_MEDIA No medium was present to load the fi= le. + @retval EFI_DEVICE_ERROR The file was not loaded due to a dev= ice error. + @retval EFI_NO_RESPONSE The remote system did not respond. + @retval EFI_NOT_FOUND The file was not found. + @retval EFI_ABORTED The file load process was manually c= ancelled. + +**/ +EFI_STATUS +EFIAPI +EfiPxeLoadFile ( + IN EFI_LOAD_FILE_PROTOCOL *This, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN BOOLEAN BootPolicy, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL + ) +{ + PXEBC_PRIVATE_DATA *Private; + PXEBC_VIRTUAL_NIC *VirtualNic; + EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; + BOOLEAN UsingIpv6; + EFI_STATUS Status; + BOOLEAN MediaPresent; + + if (FilePath =3D=3D NULL || !IsDevicePathEnd (FilePath)) { + return EFI_INVALID_PARAMETER; + } + =20 + VirtualNic =3D PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This); + Private =3D VirtualNic->Private; + PxeBc =3D &Private->PxeBc; + UsingIpv6 =3D FALSE; + Status =3D EFI_DEVICE_ERROR; + + if (This =3D=3D NULL || BufferSize =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Only support BootPolicy + // + if (!BootPolicy) { + return EFI_UNSUPPORTED; + } + + // + // Check media status before PXE start + // + MediaPresent =3D TRUE; + NetLibDetectMedia (Private->Controller, &MediaPresent); + if (!MediaPresent) { + return EFI_NO_MEDIA; + } + + // + // Check whether the virtual nic is using IPv6 or not. + // + if (VirtualNic =3D=3D Private->Ip6Nic) { + UsingIpv6 =3D TRUE; + } + + // + // Start Pxe Base Code to initialize PXE boot. + // + Status =3D PxeBc->Start (PxeBc, UsingIpv6); + if (Status =3D=3D EFI_ALREADY_STARTED && UsingIpv6 !=3D PxeBc->Mode->Usi= ngIpv6) { + // + // PxeBc protocol has already been started but not on the required IP = version, restart it. + // + Status =3D PxeBc->Stop (PxeBc); + if (!EFI_ERROR (Status)) { + Status =3D PxeBc->Start (PxeBc, UsingIpv6); + } + } + if (Status =3D=3D EFI_SUCCESS || Status =3D=3D EFI_ALREADY_STARTED) { + Status =3D PxeBcLoadBootFile (Private, BufferSize, Buffer); + } + + if (Status !=3D EFI_SUCCESS && + Status !=3D EFI_UNSUPPORTED && + Status !=3D EFI_BUFFER_TOO_SMALL) { + // + // There are three cases, which needn't stop pxebc here. + // 1. success to download file. + // 2. success to get file size. + // 3. unsupported. + // + PxeBc->Stop (PxeBc); + } else { + // + // The DHCP4 can have only one configured child instance so we need to= stop + // reset the DHCP4 child before we return. Otherwise these programs wh= ich=20 + // also need to use DHCP4 will be impacted. + // + if (!PxeBc->Mode->UsingIpv6) { + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); + } + } + + return Status; +} + +EFI_LOAD_FILE_PROTOCOL gLoadFileProtocolTemplate =3D { EfiPxeLoadFile }; + diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcImpl.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/Network= Pkg/UefiPxeBcDxe/PxeBcImpl.h new file mode 100644 index 0000000..b7d0921 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcImpl.h @@ -0,0 +1,225 @@ +/** @file + This EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL. + interfaces declaration. + + Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __EFI_PXEBC_IMPL_H__ +#define __EFI_PXEBC_IMPL_H__ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct _PXEBC_PRIVATE_DATA PXEBC_PRIVATE_DATA; +typedef struct _PXEBC_PRIVATE_PROTOCOL PXEBC_PRIVATE_PROTOCOL; +typedef struct _PXEBC_VIRTUAL_NIC PXEBC_VIRTUAL_NIC; + +#include "PxeBcDriver.h" +#include "PxeBcDhcp4.h" +#include "PxeBcDhcp6.h" +#include "PxeBcMtftp.h" +#include "PxeBcBoot.h" +#include "PxeBcSupport.h" + +#define PXEBC_DEFAULT_HOPLIMIT 64 +#define PXEBC_DEFAULT_LIFETIME 50000 // 50 ms, unit is microseco= nd +#define PXEBC_UDP_TIMEOUT 30000000 // 3 seconds, unit is 100na= nosecond +#define PXEBC_DAD_ADDITIONAL_DELAY 30000000 // 3 seconds +#define PXEBC_MTFTP_TIMEOUT 4 +#define PXEBC_MTFTP_RETRIES 6 +#define PXEBC_DHCP_RETRIES 4 // refers to mPxeDhcpTimeou= t, also by PXE2.1 spec. +#define PXEBC_MENU_MAX_NUM 24 +#define PXEBC_OFFER_MAX_NUM 16 + +#define PXEBC_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'X', 'E',= 'P') +#define PXEBC_VIRTUAL_NIC_SIGNATURE SIGNATURE_32 ('P', 'X', 'E',= 'V') +#define PXEBC_PRIVATE_DATA_FROM_PXEBC(a) CR (a, PXEBC_PRIVATE_DATA, P= xeBc, PXEBC_PRIVATE_DATA_SIGNATURE) +#define PXEBC_PRIVATE_DATA_FROM_ID(a) CR (a, PXEBC_PRIVATE_DATA, I= d, PXEBC_PRIVATE_DATA_SIGNATURE) +#define PXEBC_VIRTUAL_NIC_FROM_LOADFILE(a) CR (a, PXEBC_VIRTUAL_NIC, Lo= adFile, PXEBC_VIRTUAL_NIC_SIGNATURE) + +typedef union { + PXEBC_DHCP4_PACKET_CACHE Dhcp4; + PXEBC_DHCP6_PACKET_CACHE Dhcp6; +} PXEBC_DHCP_PACKET_CACHE; + +struct _PXEBC_PRIVATE_PROTOCOL { + UINT64 Reserved; +}; + +struct _PXEBC_VIRTUAL_NIC { + UINT32 Signature; + EFI_HANDLE Controller; + EFI_LOAD_FILE_PROTOCOL LoadFile; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + PXEBC_PRIVATE_DATA *Private; +}; + +struct _PXEBC_PRIVATE_DATA { + UINT32 Signature; + EFI_HANDLE Controller; + EFI_HANDLE Image; + + PXEBC_PRIVATE_PROTOCOL Id; + EFI_SIMPLE_NETWORK_PROTOCOL *Snp;=20 + + PXEBC_VIRTUAL_NIC *Ip4Nic; + PXEBC_VIRTUAL_NIC *Ip6Nic; + + EFI_HANDLE ArpChild; + EFI_HANDLE Ip4Child; + EFI_HANDLE Dhcp4Child; + EFI_HANDLE Mtftp4Child; + EFI_HANDLE Udp4ReadChild; + EFI_HANDLE Udp4WriteChild; + + EFI_ARP_PROTOCOL *Arp; + EFI_IP4_PROTOCOL *Ip4; + EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2; + EFI_DHCP4_PROTOCOL *Dhcp4; + EFI_MTFTP4_PROTOCOL *Mtftp4; + EFI_UDP4_PROTOCOL *Udp4Read; + EFI_UDP4_PROTOCOL *Udp4Write; + + EFI_HANDLE Ip6Child; + EFI_HANDLE Dhcp6Child; + EFI_HANDLE Mtftp6Child; + EFI_HANDLE Udp6ReadChild; + EFI_HANDLE Udp6WriteChild; + + EFI_IP6_PROTOCOL *Ip6; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_DHCP6_PROTOCOL *Dhcp6; + EFI_MTFTP6_PROTOCOL *Mtftp6; + EFI_UDP6_PROTOCOL *Udp6Read; + EFI_UDP6_PROTOCOL *Udp6Write; + + EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii; + EFI_PXE_BASE_CODE_PROTOCOL PxeBc; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL LoadFileCallback; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *PxeBcCallback; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + EFI_PXE_BASE_CODE_MODE Mode; + EFI_PXE_BASE_CODE_FUNCTION Function; + UINT32 Ip6Policy; + UINT32 SolicitTimes; + UINT64 ElapsedTime; + + EFI_UDP4_CONFIG_DATA Udp4CfgData; + EFI_UDP6_CONFIG_DATA Udp6CfgData; + EFI_IP4_CONFIG_DATA Ip4CfgData; + EFI_IP6_CONFIG_DATA Ip6CfgData; + + EFI_EVENT UdpTimeOutEvent; + EFI_EVENT ArpUpdateEvent; + EFI_IP4_COMPLETION_TOKEN IcmpToken; + EFI_IP6_COMPLETION_TOKEN Icmp6Token; + + BOOLEAN IsAddressOk; + BOOLEAN IsOfferSorted; + BOOLEAN IsProxyRecved; + BOOLEAN IsDoDiscover; + + EFI_IP_ADDRESS TmpStationIp; + EFI_IP_ADDRESS StationIp; + EFI_IP_ADDRESS SubnetMask; + EFI_IP_ADDRESS GatewayIp; + EFI_IP_ADDRESS ServerIp; + UINT16 CurSrcPort; + UINT32 IaId; + + UINT32 Ip4MaxPacketSize; + UINT32 Ip6MaxPacketSize; + UINT8 *BootFileName; + UINTN BootFileSize; + UINTN BlockSize; + + PXEBC_DHCP_PACKET_CACHE ProxyOffer; + PXEBC_DHCP_PACKET_CACHE DhcpAck; + PXEBC_DHCP_PACKET_CACHE PxeReply; + EFI_DHCP6_PACKET *Dhcp6Request; + EFI_DHCP4_PACKET SeedPacket; + + // + // OfferIndex records the index of DhcpOffer[] buffer, and OfferCount re= cords the num of each type of offer. + // + // It supposed that + // + // OfferNum: 8 + // OfferBuffer: [ProxyBinl, ProxyBinl, DhcpOnly, ProxyPxe10, DhcpOnly,= DhcpPxe10, DhcpBinl, ProxyBinl] + // (OfferBuffer is 0-based.) + // + // And assume that (DhcpPxe10 is the first priority actually.) + // + // SelectIndex: 2 + // SelectProxyType: PXEBC_OFFER_TYPE_PROXY_BINL + // (SelectIndex is 1-based, and 0 means no one is selected.) + // + // So it should be + // + // DhcpOnly DhcpPxe10 DhcpWfm11a DhcpBinl ProxyPxe10= ProxyWfm11a ProxyBinl Bootp + // OfferCount: [ 2(n), 1(n), 0(n), 1(n), 1(1)= , 0(1), 3(n), 1(1)] + // + // OfferIndex: {[ 2, 5, 0, 6, 3= , 0, *0, 0] + // [ 4, 0, 0, 0, 0= , 0, 1, 0] + // [ 0, 0, 0, 0, 0= , 0, 7, 0] + // ... = ]} + // (OfferIndex is 0-based.) + // + // + UINT32 SelectIndex; + UINT32 SelectProxyType; + PXEBC_DHCP_PACKET_CACHE OfferBuffer[PXEBC_OFFER_MAX_NU= M]; + UINT32 OfferNum; + UINT32 OfferCount[PxeOfferTypeMax]; + UINT32 OfferIndex[PxeOfferTypeMax][PX= EBC_OFFER_MAX_NUM]; +}; + +extern EFI_PXE_BASE_CODE_PROTOCOL gPxeBcProtocolTemplate; +extern EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL gPxeBcCallBackTemplate; +extern EFI_LOAD_FILE_PROTOCOL gLoadFileProtocolTemplate; + +#endif diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcMtftp.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Networ= kPkg/UefiPxeBcDxe/PxeBcMtftp.c new file mode 100644 index 0000000..61c8f84 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcMtftp.c @@ -0,0 +1,1113 @@ +/** @file + Functions implementation related with Mtftp for UefiPxeBc Driver. + + Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + +CHAR8 *mMtftpOptions[PXE_MTFTP_OPTION_MAXIMUM_INDEX] =3D { + "blksize", + "timeout", + "tsize", + "multicast" +}; + + +/** + This is a callback function when packets are received or transmitted in = Mtftp driver. + + A callback function that is provided by the caller to intercept + the EFI_MTFTP6_OPCODE_DATA or EFI_MTFTP6_OPCODE_DATA8 packets processed = in the + EFI_MTFTP6_PROTOCOL.ReadFile() function, and alternatively to intercept + EFI_MTFTP6_OPCODE_OACK or EFI_MTFTP6_OPCODE_ERROR packets during a call = to + EFI_MTFTP6_PROTOCOL.ReadFile(), WriteFile() or ReadDirectory(). + + @param[in] This Pointer to EFI_MTFTP6_PROTOCOL. + @param[in] Token Pointer to EFI_MTFTP6_TOKEN. + @param[in] PacketLen Length of EFI_MTFTP6_PACKET. + @param[in] Packet Pointer to EFI_MTFTP6_PACKET to be checked. + + @retval EFI_SUCCESS The current operation succeeded. + @retval EFI_ABORTED Abort the current transfer process. + +**/ +EFI_STATUS +EFIAPI +PxeBcMtftp6CheckPacket ( + IN EFI_MTFTP6_PROTOCOL *This, + IN EFI_MTFTP6_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP6_PACKET *Packet + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; + EFI_STATUS Status; + + Private =3D (PXEBC_PRIVATE_DATA *) Token->Context; + Callback =3D Private->PxeBcCallback; + Status =3D EFI_SUCCESS; + + if (Packet->OpCode =3D=3D EFI_MTFTP6_OPCODE_ERROR) { + // + // Store the tftp error message into mode data and set the received fl= ag. + // + Private->Mode.TftpErrorReceived =3D TRUE; + Private->Mode.TftpError.ErrorCode =3D (UINT8) Packet->Error.ErrorCode; + AsciiStrnCpyS ( + Private->Mode.TftpError.ErrorString, + PXE_MTFTP_ERROR_STRING_LENGTH, + (CHAR8 *) Packet->Error.ErrorMessage, + PXE_MTFTP_ERROR_STRING_LENGTH - 1 + ); + Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1]= =3D '\0'; + } + + if (Callback !=3D NULL) { + // + // Callback to user if has when received any tftp packet. + // + Status =3D Callback->Callback ( + Callback, + Private->Function, + TRUE, + PacketLen, + (EFI_PXE_BASE_CODE_PACKET *) Packet + ); + if (Status !=3D EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + // + // User wants to abort current process if not EFI_PXE_BASE_CODE_CALL= BACK_STATUS_CONTINUE. + // + Status =3D EFI_ABORTED; + } else { + // + // User wants to continue current process if EFI_PXE_BASE_CODE_CALLB= ACK_STATUS_CONTINUE. + // + Status =3D EFI_SUCCESS; + } + } + + return Status; +} + + +/** + This function is to get the size of a file using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP6_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Sucessfully obtained the size of file. + @retval EFI_NOT_FOUND Parse the tftp ptions failed. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Has not obtained the size of the file. + +**/ +EFI_STATUS +PxeBcMtftp6GetFileSize ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP6_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN OUT UINT64 *BufferSize + ) +{ + EFI_MTFTP6_PROTOCOL *Mtftp6; + EFI_MTFTP6_OPTION ReqOpt[2]; + EFI_MTFTP6_PACKET *Packet; + EFI_MTFTP6_OPTION *Option; + UINT32 PktLen; + UINT8 OptBuf[128]; + UINT32 OptCnt; + EFI_STATUS Status; + + *BufferSize =3D 0; + Status =3D EFI_DEVICE_ERROR; + Mtftp6 =3D Private->Mtftp6; + Packet =3D NULL; + Option =3D NULL; + PktLen =3D 0; + OptCnt =3D 1; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp6->Configure (Mtftp6, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Build the required options for get info. + // + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_TSIZE_I= NDEX]; + PxeBcUintnToAscDec (0, OptBuf, PXE_MTFTP_OPTBUF_MAXNUM_INDEX); + ReqOpt[0].ValueStr =3D OptBuf; + + if (BlockSize !=3D NULL) { + ReqOpt[1].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[1].ValueStr =3D (UINT8 *) (ReqOpt[0].ValueStr + AsciiStrLen ((= CHAR8 *) ReqOpt[0].ValueStr) + 1); + PxeBcUintnToAscDec (*BlockSize, ReqOpt[1].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX - (AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1)); + OptCnt++; + } + + Status =3D Mtftp6->GetInfo ( + Mtftp6, + NULL, + Filename, + NULL, + (UINT8) OptCnt, + ReqOpt, + &PktLen, + &Packet + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_TFTP_ERROR) { + // + // Store the tftp error message into mode data and set the received = flag. + // + Private->Mode.TftpErrorReceived =3D TRUE; + Private->Mode.TftpError.ErrorCode =3D (UINT8) Packet->Error.ErrorCod= e; + AsciiStrnCpyS ( + Private->Mode.TftpError.ErrorString, + PXE_MTFTP_ERROR_STRING_LENGTH, + (CHAR8 *) Packet->Error.ErrorMessage, + PXE_MTFTP_ERROR_STRING_LENGTH - 1 + ); + Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - = 1] =3D '\0'; + } + goto ON_ERROR; + } + + // + // Parse the options in the reply packet. + // + OptCnt =3D 0; + Status =3D Mtftp6->ParseOptions ( + Mtftp6, + PktLen, + Packet, + (UINT32 *) &OptCnt, + &Option + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Parse out the value of "tsize" option. + // + Status =3D EFI_NOT_FOUND; + while (OptCnt !=3D 0) { + if (AsciiStrnCmp ((CHAR8 *) Option[OptCnt - 1].OptionStr, "tsize", 5) = =3D=3D 0) { + *BufferSize =3D AsciiStrDecimalToUint64 ((CHAR8 *) (Option[OptCnt - = 1].ValueStr)); + Status =3D EFI_SUCCESS; + } + OptCnt--; + } + FreePool (Option); + +ON_ERROR: + if (Packet !=3D NULL) { + FreePool (Packet); + } + Mtftp6->Configure (Mtftp6, NULL); + + return Status; +} + + +/** + This function is to get data of a file using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP6_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicates whether with a receive buffer. + + @retval EFI_SUCCESS Successfully read the data from the special f= ile. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Read data from file failed. + +**/ +EFI_STATUS +PxeBcMtftp6ReadFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP6_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ) +{ + EFI_MTFTP6_PROTOCOL *Mtftp6; + EFI_MTFTP6_TOKEN Token; + EFI_MTFTP6_OPTION ReqOpt[1]; + UINT32 OptCnt; + UINT8 OptBuf[128]; + EFI_STATUS Status; + + Status =3D EFI_DEVICE_ERROR; + Mtftp6 =3D Private->Mtftp6; + OptCnt =3D 0; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp6->Configure (Mtftp6, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + if (BlockSize !=3D NULL) { + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[0].ValueStr =3D OptBuf; + PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX); + OptCnt++; + } + + Token.Event =3D NULL; + Token.OverrideData =3D NULL; + Token.Filename =3D Filename; + Token.ModeStr =3D NULL; + Token.OptionCount =3D OptCnt; + Token.OptionList =3D ReqOpt; + Token.Context =3D Private; + + if (DontUseBuffer) { + Token.BufferSize =3D 0; + Token.Buffer =3D NULL; + } else { + Token.BufferSize =3D *BufferSize; + Token.Buffer =3D BufferPtr; + } + + Token.CheckPacket =3D PxeBcMtftp6CheckPacket; + Token.TimeoutCallback =3D NULL; + Token.PacketNeeded =3D NULL; + + Status =3D Mtftp6->ReadFile (Mtftp6, &Token); + // + // Get the real size of received buffer. + // + *BufferSize =3D Token.BufferSize; + + Mtftp6->Configure (Mtftp6, NULL); + + return Status; +} + + +/** + This function is used to write the data of a file using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP6_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] Overwrite Indicate whether with overwrite attribut= e. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Successfully wrote the data into a special fi= le. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval other Write data into file failed. + +**/ +EFI_STATUS +PxeBcMtftp6WriteFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP6_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN BOOLEAN Overwrite, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize + ) +{ + EFI_MTFTP6_PROTOCOL *Mtftp6; + EFI_MTFTP6_TOKEN Token; + EFI_MTFTP6_OPTION ReqOpt[1]; + UINT32 OptCnt; + UINT8 OptBuf[128]; + EFI_STATUS Status; + + Status =3D EFI_DEVICE_ERROR; + Mtftp6 =3D Private->Mtftp6; + OptCnt =3D 0; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp6->Configure (Mtftp6, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + if (BlockSize !=3D NULL) { + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[0].ValueStr =3D OptBuf; + PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX); + OptCnt++; + } + + Token.Event =3D NULL; + Token.OverrideData =3D NULL; + Token.Filename =3D Filename; + Token.ModeStr =3D NULL; + Token.OptionCount =3D OptCnt; + Token.OptionList =3D ReqOpt; + Token.BufferSize =3D *BufferSize; + Token.Buffer =3D BufferPtr; + Token.CheckPacket =3D PxeBcMtftp6CheckPacket; + Token.TimeoutCallback =3D NULL; + Token.PacketNeeded =3D NULL; + + Status =3D Mtftp6->WriteFile (Mtftp6, &Token); + // + // Get the real size of transmitted buffer. + // + *BufferSize =3D Token.BufferSize; + + Mtftp6->Configure (Mtftp6, NULL); + + return Status; +} + + +/** + This function is to read the data (file) from a directory using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP6_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicates whether to use a receive buffe= r. + + @retval EFI_SUCCESS Successfully obtained the data from the file = included in directory. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Operation failed. + +**/ +EFI_STATUS +PxeBcMtftp6ReadDirectory ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP6_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ) +{ + EFI_MTFTP6_PROTOCOL *Mtftp6; + EFI_MTFTP6_TOKEN Token; + EFI_MTFTP6_OPTION ReqOpt[1]; + UINT32 OptCnt; + UINT8 OptBuf[128]; + EFI_STATUS Status; + + Status =3D EFI_DEVICE_ERROR; + Mtftp6 =3D Private->Mtftp6; + OptCnt =3D 0; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp6->Configure (Mtftp6, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + if (BlockSize !=3D NULL) { + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[0].ValueStr =3D OptBuf; + PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX); + OptCnt++; + } + + Token.Event =3D NULL; + Token.OverrideData =3D NULL; + Token.Filename =3D Filename; + Token.ModeStr =3D NULL; + Token.OptionCount =3D OptCnt; + Token.OptionList =3D ReqOpt; + Token.Context =3D Private; + + if (DontUseBuffer) { + Token.BufferSize =3D 0; + Token.Buffer =3D NULL; + } else { + Token.BufferSize =3D *BufferSize; + Token.Buffer =3D BufferPtr; + } + + Token.CheckPacket =3D PxeBcMtftp6CheckPacket; + Token.TimeoutCallback =3D NULL; + Token.PacketNeeded =3D NULL; + + Status =3D Mtftp6->ReadDirectory (Mtftp6, &Token); + // + // Get the real size of received buffer. + // + *BufferSize =3D Token.BufferSize; + + Mtftp6->Configure (Mtftp6, NULL); + + return Status; +} + + +/** + This is a callback function when packets are received or transmitted in = Mtftp driver. + + A callback function that is provided by the caller to intercept + the EFI_MTFTP6_OPCODE_DATA or EFI_MTFTP4_OPCODE_DATA8 packets processed = in the + EFI_MTFTP4_PROTOCOL.ReadFile() function, and alternatively to intercept + EFI_MTFTP4_OPCODE_OACK or EFI_MTFTP4_OPCODE_ERROR packets during a call = to + EFI_MTFTP4_PROTOCOL.ReadFile(), WriteFile() or ReadDirectory(). + + @param[in] This Pointer to EFI_MTFTP4_PROTOCOL. + @param[in] Token Pointer to EFI_MTFTP4_TOKEN. + @param[in] PacketLen Length of EFI_MTFTP4_PACKET. + @param[in] Packet Pointer to EFI_MTFTP4_PACKET to be checked. + + @retval EFI_SUCCESS The current operation succeeeded. + @retval EFI_ABORTED Abort the current transfer process. + +**/ +EFI_STATUS +EFIAPI +PxeBcMtftp4CheckPacket ( + IN EFI_MTFTP4_PROTOCOL *This, + IN EFI_MTFTP4_TOKEN *Token, + IN UINT16 PacketLen, + IN EFI_MTFTP4_PACKET *Packet + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback; + EFI_STATUS Status; + + Private =3D (PXEBC_PRIVATE_DATA *) Token->Context; + Callback =3D Private->PxeBcCallback; + Status =3D EFI_SUCCESS; + + if (Packet->OpCode =3D=3D EFI_MTFTP4_OPCODE_ERROR) { + // + // Store the tftp error message into mode data and set the received fl= ag. + // + Private->Mode.TftpErrorReceived =3D TRUE; + Private->Mode.TftpError.ErrorCode =3D (UINT8) Packet->Error.ErrorCode; + AsciiStrnCpyS ( + Private->Mode.TftpError.ErrorString, + PXE_MTFTP_ERROR_STRING_LENGTH, + (CHAR8 *) Packet->Error.ErrorMessage, + PXE_MTFTP_ERROR_STRING_LENGTH - 1 + ); + Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - 1]= =3D '\0'; + } + + if (Callback !=3D NULL) { + // + // Callback to user if has when received any tftp packet. + // + Status =3D Callback->Callback ( + Callback, + Private->Function, + TRUE, + PacketLen, + (EFI_PXE_BASE_CODE_PACKET *) Packet + ); + if (Status !=3D EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) { + // + // User wants to abort current process if not EFI_PXE_BASE_CODE_CALL= BACK_STATUS_CONTINUE. + // + Status =3D EFI_ABORTED; + } else { + // + // User wants to continue current process if EFI_PXE_BASE_CODE_CALLB= ACK_STATUS_CONTINUE. + // + Status =3D EFI_SUCCESS; + } + } + + return Status; +} + + +/** + This function is to get size of a file using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP4_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Successfully obtained the size of file. + @retval EFI_NOT_FOUND Parse the tftp options failed. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Did not obtain the size of the file. + +**/ +EFI_STATUS +PxeBcMtftp4GetFileSize ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP4_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN OUT UINT64 *BufferSize + ) +{ + EFI_MTFTP4_PROTOCOL *Mtftp4; + EFI_MTFTP4_OPTION ReqOpt[2]; + EFI_MTFTP4_PACKET *Packet; + EFI_MTFTP4_OPTION *Option; + UINT32 PktLen; + UINT8 OptBuf[128]; + UINT32 OptCnt; + EFI_STATUS Status; + + *BufferSize =3D 0; + Status =3D EFI_DEVICE_ERROR; + Mtftp4 =3D Private->Mtftp4; + Packet =3D NULL; + Option =3D NULL; + PktLen =3D 0; + OptCnt =3D 1; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp4->Configure (Mtftp4, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Build the required options for get info. + // + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_TSIZE_I= NDEX]; + PxeBcUintnToAscDec (0, OptBuf, PXE_MTFTP_OPTBUF_MAXNUM_INDEX); + ReqOpt[0].ValueStr =3D OptBuf; + + if (BlockSize !=3D NULL) { + ReqOpt[1].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[1].ValueStr =3D (UINT8 *) (ReqOpt[0].ValueStr + AsciiStrLen ((= CHAR8 *) ReqOpt[0].ValueStr) + 1); + PxeBcUintnToAscDec (*BlockSize, ReqOpt[1].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX - (AsciiStrLen ((CHAR8 *) ReqOpt[0].ValueStr) + 1)); + OptCnt++; + } + + Status =3D Mtftp4->GetInfo ( + Mtftp4, + NULL, + Filename, + NULL, + (UINT8) OptCnt, + ReqOpt, + &PktLen, + &Packet + ); + if (EFI_ERROR (Status)) { + if (Status =3D=3D EFI_TFTP_ERROR) { + // + // Store the tftp error message into mode data and set the received = flag. + // + Private->Mode.TftpErrorReceived =3D TRUE; + Private->Mode.TftpError.ErrorCode =3D (UINT8) Packet->Error.ErrorCod= e; + AsciiStrnCpyS ( + Private->Mode.TftpError.ErrorString, + PXE_MTFTP_ERROR_STRING_LENGTH, + (CHAR8 *) Packet->Error.ErrorMessage, + PXE_MTFTP_ERROR_STRING_LENGTH - 1 + ); + Private->Mode.TftpError.ErrorString[PXE_MTFTP_ERROR_STRING_LENGTH - = 1] =3D '\0'; + } + goto ON_ERROR; + } + + // + // Parse the options in the reply packet. + // + OptCnt =3D 0; + Status =3D Mtftp4->ParseOptions ( + Mtftp4, + PktLen, + Packet, + (UINT32 *) &OptCnt, + &Option + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + + // + // Parse out the value of "tsize" option. + // + Status =3D EFI_NOT_FOUND; + while (OptCnt !=3D 0) { + if (AsciiStrnCmp ((CHAR8 *) Option[OptCnt - 1].OptionStr, "tsize", 5) = =3D=3D 0) { + *BufferSize =3D AsciiStrDecimalToUint64 ((CHAR8 *) (Option[OptCnt - = 1].ValueStr)); + Status =3D EFI_SUCCESS; + } + OptCnt--; + } + FreePool (Option); + +ON_ERROR: + if (Packet !=3D NULL) { + FreePool (Packet); + } + Mtftp4->Configure (Mtftp4, NULL); + + return Status; +} + + +/** + This function is to read the data of a file using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP4_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicates whether to use a receive buffer= . + + @retval EFI_SUCCESS Successfully read the data from the special f= ile. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Read data from file failed. + +**/ +EFI_STATUS +PxeBcMtftp4ReadFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP4_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ) +{ + EFI_MTFTP4_PROTOCOL *Mtftp4; + EFI_MTFTP4_TOKEN Token; + EFI_MTFTP4_OPTION ReqOpt[1]; + UINT32 OptCnt; + UINT8 OptBuf[128]; + EFI_STATUS Status; + + Status =3D EFI_DEVICE_ERROR; + Mtftp4 =3D Private->Mtftp4; + OptCnt =3D 0; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp4->Configure (Mtftp4, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + if (BlockSize !=3D NULL) { + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[0].ValueStr =3D OptBuf; + PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX); + OptCnt++; + } + + Token.Event =3D NULL; + Token.OverrideData =3D NULL; + Token.Filename =3D Filename; + Token.ModeStr =3D NULL; + Token.OptionCount =3D OptCnt; + Token.OptionList =3D ReqOpt; + Token.Context =3D Private; + + if (DontUseBuffer) { + Token.BufferSize =3D 0; + Token.Buffer =3D NULL; + } else { + Token.BufferSize =3D *BufferSize; + Token.Buffer =3D BufferPtr; + } + + Token.CheckPacket =3D PxeBcMtftp4CheckPacket; + Token.TimeoutCallback =3D NULL; + Token.PacketNeeded =3D NULL; + + Status =3D Mtftp4->ReadFile (Mtftp4, &Token); + // + // Get the real size of received buffer. + // + *BufferSize =3D Token.BufferSize; + + Mtftp4->Configure (Mtftp4, NULL); + + return Status; +} + + +/** + This function is to write the data of a file using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP4_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] Overwrite Indicates whether to use the overwrite a= ttribute. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Successfully write the data into the special= file. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval other Write data into file failed. + +**/ +EFI_STATUS +PxeBcMtftp4WriteFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP4_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN BOOLEAN Overwrite, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize + ) +{ + EFI_MTFTP4_PROTOCOL *Mtftp4; + EFI_MTFTP4_TOKEN Token; + EFI_MTFTP4_OPTION ReqOpt[1]; + UINT32 OptCnt; + UINT8 OptBuf[128]; + EFI_STATUS Status; + + Status =3D EFI_DEVICE_ERROR; + Mtftp4 =3D Private->Mtftp4; + OptCnt =3D 0; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp4->Configure (Mtftp4, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + if (BlockSize !=3D NULL) { + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[0].ValueStr =3D OptBuf; + PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX); + OptCnt++; + } + + Token.Event =3D NULL; + Token.OverrideData =3D NULL; + Token.Filename =3D Filename; + Token.ModeStr =3D NULL; + Token.OptionCount =3D OptCnt; + Token.OptionList =3D ReqOpt; + Token.BufferSize =3D *BufferSize; + Token.Buffer =3D BufferPtr; + Token.CheckPacket =3D PxeBcMtftp4CheckPacket; + Token.TimeoutCallback =3D NULL; + Token.PacketNeeded =3D NULL; + + Status =3D Mtftp4->WriteFile (Mtftp4, &Token); + // + // Get the real size of transmitted buffer. + // + *BufferSize =3D Token.BufferSize; + + Mtftp4->Configure (Mtftp4, NULL); + + return Status; +} + + +/** + This function is to get data (file) from a directory using Tftp. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to EFI_MTFTP4_CONFIG_DATA. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicates whether to use a receive buffe= r. + + @retval EFI_SUCCES Successfully obtained the data from the file = included in the directory. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Operation failed. + +**/ +EFI_STATUS +PxeBcMtftp4ReadDirectory ( + IN PXEBC_PRIVATE_DATA *Private, + IN EFI_MTFTP4_CONFIG_DATA *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ) +{ + EFI_MTFTP4_PROTOCOL *Mtftp4; + EFI_MTFTP4_TOKEN Token; + EFI_MTFTP4_OPTION ReqOpt[1]; + UINT32 OptCnt; + UINT8 OptBuf[128]; + EFI_STATUS Status; + + Status =3D EFI_DEVICE_ERROR; + Mtftp4 =3D Private->Mtftp4; + OptCnt =3D 0; + Config->InitialServerPort =3D PXEBC_BS_DOWNLOAD_PORT; + + Status =3D Mtftp4->Configure (Mtftp4, Config); + if (EFI_ERROR (Status)) { + return Status; + } + + if (BlockSize !=3D NULL) { + ReqOpt[0].OptionStr =3D (UINT8 *) mMtftpOptions[PXE_MTFTP_OPTION_BLKSI= ZE_INDEX]; + ReqOpt[0].ValueStr =3D OptBuf; + PxeBcUintnToAscDec (*BlockSize, ReqOpt[0].ValueStr, PXE_MTFTP_OPTBUF_M= AXNUM_INDEX); + OptCnt++; + } + + Token.Event =3D NULL; + Token.OverrideData =3D NULL; + Token.Filename =3D Filename; + Token.ModeStr =3D NULL; + Token.OptionCount =3D OptCnt; + Token.OptionList =3D ReqOpt; + Token.Context =3D Private; + + if (DontUseBuffer) { + Token.BufferSize =3D 0; + Token.Buffer =3D NULL; + } else { + Token.BufferSize =3D *BufferSize; + Token.Buffer =3D BufferPtr; + } + + Token.CheckPacket =3D PxeBcMtftp4CheckPacket; + Token.TimeoutCallback =3D NULL; + Token.PacketNeeded =3D NULL; + + Status =3D Mtftp4->ReadDirectory (Mtftp4, &Token); + // + // Get the real size of received buffer. + // + *BufferSize =3D Token.BufferSize; + + Mtftp4->Configure (Mtftp4, NULL); + + return Status; +} + + +/** + This function is wrapper to get the file size using TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to configure data. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Successfully obtained the size of file. + @retval EFI_NOT_FOUND Parse the tftp options failed. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Did not obtain the size of the file. + +**/ +EFI_STATUS +PxeBcTftpGetFileSize ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN OUT UINT64 *BufferSize + ) +{ + if (Private->PxeBc.Mode->UsingIpv6) { + return PxeBcMtftp6GetFileSize ( + Private, + (EFI_MTFTP6_CONFIG_DATA *) Config, + Filename, + BlockSize, + BufferSize + ); + } else { + return PxeBcMtftp4GetFileSize ( + Private, + (EFI_MTFTP4_CONFIG_DATA *) Config, + Filename, + BlockSize, + BufferSize + ); + } +} + + +/** + This function is a wrapper to get file using TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to config data. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicates whether to use a receive buffer= . + + @retval EFI_SUCCESS Sucessfully read the data from the special fi= le. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Read data from file failed. + +**/ +EFI_STATUS +PxeBcTftpReadFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ) +{ + if (Private->PxeBc.Mode->UsingIpv6) { + return PxeBcMtftp6ReadFile ( + Private, + (EFI_MTFTP6_CONFIG_DATA *) Config, + Filename, + BlockSize, + BufferPtr, + BufferSize, + DontUseBuffer + ); + } else { + return PxeBcMtftp4ReadFile ( + Private, + (EFI_MTFTP4_CONFIG_DATA *) Config, + Filename, + BlockSize, + BufferPtr, + BufferSize, + DontUseBuffer + ); + } +} + + +/** + This function is a wrapper to write file using TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to config data. + @param[in] Filename Pointer to boot file name. + @param[in] Overwrite Indicate whether with overwrite attribut= e. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Successfully wrote the data into a special fi= le. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval other Write data into file failed. + +**/ +EFI_STATUS +PxeBcTftpWriteFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN BOOLEAN Overwrite, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize + ) +{ + if (Private->PxeBc.Mode->UsingIpv6) { + return PxeBcMtftp6WriteFile ( + Private, + (EFI_MTFTP6_CONFIG_DATA *) Config, + Filename, + Overwrite, + BlockSize, + BufferPtr, + BufferSize + ); + } else { + return PxeBcMtftp4WriteFile ( + Private, + (EFI_MTFTP4_CONFIG_DATA *) Config, + Filename, + Overwrite, + BlockSize, + BufferPtr, + BufferSize + ); + } +} + + +/** + This function is a wrapper to get the data (file) from a directory using= TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to config data. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicatse whether to use a receive buffe= r. + + @retval EFI_SUCCES Successfully obtained the data from the file = included in the directory. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Operation failed. + +**/ +EFI_STATUS +PxeBcTftpReadDirectory ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ) +{ + if (Private->PxeBc.Mode->UsingIpv6) { + return PxeBcMtftp6ReadDirectory ( + Private, + (EFI_MTFTP6_CONFIG_DATA *) Config, + Filename, + BlockSize, + BufferPtr, + BufferSize, + DontUseBuffer + ); + } else { + return PxeBcMtftp4ReadDirectory ( + Private, + (EFI_MTFTP4_CONFIG_DATA *) Config, + Filename, + BlockSize, + BufferPtr, + BufferSize, + DontUseBuffer + ); + } +} + diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcMtftp.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/Networ= kPkg/UefiPxeBcDxe/PxeBcMtftp.h new file mode 100644 index 0000000..2935b0a --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcMtftp.h @@ -0,0 +1,137 @@ +/** @file + Functions declaration related with Mtftp for UefiPxeBc Driver. + + Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __EFI_PXEBC_MTFTP_H__ +#define __EFI_PXEBC_MTFTP_H__ + +#define PXE_MTFTP_OPTION_BLKSIZE_INDEX 0 +#define PXE_MTFTP_OPTION_TIMEOUT_INDEX 1 +#define PXE_MTFTP_OPTION_TSIZE_INDEX 2 +#define PXE_MTFTP_OPTION_MULTICAST_INDEX 3 +#define PXE_MTFTP_OPTION_MAXIMUM_INDEX 4 +#define PXE_MTFTP_OPTBUF_MAXNUM_INDEX 128 + +#define PXE_MTFTP_ERROR_STRING_LENGTH 127 // refer to definition of= struct EFI_PXE_BASE_CODE_TFTP_ERROR. +#define PXE_MTFTP_DEFAULT_BLOCK_SIZE 512 // refer to rfc-1350. + + +/** + This function is wrapper to get the file size using TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to configure data. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Successfully obtained the size of file. + @retval EFI_NOT_FOUND Parse the tftp ptions failed. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Did not obtain the size of the file. + +**/ +EFI_STATUS +PxeBcTftpGetFileSize ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN OUT UINT64 *BufferSize + ); + + +/** + This function is a wrapper to get a file using TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to config data. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicates whether to use a receive buffer= . + + @retval EFI_SUCCESS Successfully read the data from the special f= ile. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Read data from file failed. + +**/ +EFI_STATUS +PxeBcTftpReadFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ); + + +/** + This function is a wrapper to put file with TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to config data. + @param[in] Filename Pointer to boot file name. + @param[in] Overwrite Indicates whether to use an overwrite at= tribute. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + + @retval EFI_SUCCESS Successfully wrote the data into the special = file. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval other Write data into file failed. + +**/ +EFI_STATUS +PxeBcTftpWriteFile ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN BOOLEAN Overwrite, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize + ); + + +/** + This function is a wrapper to get the data (file) from a directory using= TFTP. + + @param[in] Private Pointer to PxeBc private data. + @param[in] Config Pointer to config data. + @param[in] Filename Pointer to boot file name. + @param[in] BlockSize Pointer to required block size. + @param[in] BufferPtr Pointer to buffer. + @param[in, out] BufferSize Pointer to buffer size. + @param[in] DontUseBuffer Indicates whether with a receive buffer. + + @retval EFI_SUCCES Successfully obtained the data from the file = included in directory. + @retval EFI_DEVICE_ERROR The network device encountered an error durin= g this operation. + @retval Others Operation failed. + +**/ +EFI_STATUS +PxeBcTftpReadDirectory ( + IN PXEBC_PRIVATE_DATA *Private, + IN VOID *Config, + IN UINT8 *Filename, + IN UINTN *BlockSize, + IN UINT8 *BufferPtr, + IN OUT UINT64 *BufferSize, + IN BOOLEAN DontUseBuffer + ); +#endif diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcSupport.c b/Platform/BroxtonPlatformPkg/Common/SampleCode/Netw= orkPkg/UefiPxeBcDxe/PxeBcSupport.c new file mode 100644 index 0000000..e8d64a3 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcSupport.c @@ -0,0 +1,1513 @@ +/** @file + Support functions implementation for UefiPxeBc Driver. + + Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#include "PxeBcImpl.h" + + +/** + Flush the previous configration using the new station Ip address. + + @param[in] Private The pointer to the PxeBc private data. + @param[in] StationIp The pointer to the station Ip address. + @param[in] SubnetMask The pointer to the subnet mask address for v= 4. + + @retval EFI_SUCCESS Successfully flushed the previous configurat= ion. + @retval Others Failed to flush using the new station Ip. + +**/ +EFI_STATUS +PxeBcFlushStationIp ( + PXEBC_PRIVATE_DATA *Private, + EFI_IP_ADDRESS *StationIp, + EFI_IP_ADDRESS *SubnetMask OPTIONAL + ) +{ + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_STATUS Status; + + ASSERT (StationIp !=3D NULL); + + Mode =3D Private->PxeBc.Mode; + Status =3D EFI_SUCCESS; + + if (Mode->UsingIpv6) { + + CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_= IPv6_ADDRESS)); + CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_I= Pv6_ADDRESS)); + + // + // Reconfigure the Ip6 instance to capture background ICMP6 packets wi= th new station Ip address. + // + Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token); + Private->Ip6->Configure (Private->Ip6, NULL); + + Status =3D Private->Ip6->Configure (Private->Ip6, &Private->Ip6CfgData= ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status =3D Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token); + } else { + ASSERT (SubnetMask !=3D NULL); + CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_= IPv4_ADDRESS)); + CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv= 4_ADDRESS)); + CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_I= Pv4_ADDRESS)); + CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4= _ADDRESS)); + + // + // Reconfigure the Ip4 instance to capture background ICMP packets wit= h new station Ip address. + // + Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken); + Private->Ip4->Configure (Private->Ip4, NULL); + + Status =3D Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData= ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status =3D Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken); + } + +ON_EXIT: + return Status; +} + + +/** + Notify the callback function when an event is triggered. + + @param[in] Event The triggered event. + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +PxeBcCommonNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + *((BOOLEAN *) Context) =3D TRUE; +} + + +/** + Do arp resolution from arp cache in PxeBcMode. + + @param Mode The pointer to EFI_PXE_BASE_CODE_MODE. + @param Ip4Addr The Ip4 address for resolution. + @param MacAddress The resoluted MAC address if the resolution is su= ccessful. + The value is undefined if the resolution fails. + + @retval TRUE Found an matched entry. + @retval FALSE Did not find a matched entry. + +**/ +BOOLEAN +PxeBcCheckArpCache ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN EFI_IPv4_ADDRESS *Ip4Addr, + OUT EFI_MAC_ADDRESS *MacAddress + ) +{ + UINT32 Index; + + ASSERT (!Mode->UsingIpv6); + + // + // Check whether the current Arp cache in mode data contains this inform= ation or not. + // + for (Index =3D 0; Index < Mode->ArpCacheEntries; Index++) { + if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) { + CopyMem ( + MacAddress, + &Mode->ArpCache[Index].MacAddr, + sizeof (EFI_MAC_ADDRESS) + ); + return TRUE; + } + } + + return FALSE; +} + + +/** + Update the arp cache periodically. + + @param Event The pointer to EFI_PXE_BC_PROTOCOL. + @param Context Context of the timer event. + +**/ +VOID +EFIAPI +PxeBcArpCacheUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_ARP_FIND_DATA *ArpEntry; + UINT32 EntryLength; + UINT32 EntryCount; + UINT32 Index; + EFI_STATUS Status; + + Private =3D (PXEBC_PRIVATE_DATA *) Context; + Mode =3D Private->PxeBc.Mode; + + ASSERT (!Mode->UsingIpv6); + + // + // Get the current Arp cache from Arp driver. + // + Status =3D Private->Arp->Find ( + Private->Arp, + TRUE, + NULL, + &EntryLength, + &EntryCount, + &ArpEntry, + TRUE + ); + if (EFI_ERROR (Status)) { + return; + } + + // + // Update the Arp cache in mode data. + // + Mode->ArpCacheEntries =3D MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENT= RIES); + + for (Index =3D 0; Index < Mode->ArpCacheEntries; Index++) { + CopyMem ( + &Mode->ArpCache[Index].IpAddr, + ArpEntry + 1, + ArpEntry->SwAddressLength + ); + CopyMem ( + &Mode->ArpCache[Index].MacAddr, + (UINT8 *) (ArpEntry + 1) + ArpEntry->SwAddressLength, + ArpEntry->HwAddressLength + ); + ArpEntry =3D (EFI_ARP_FIND_DATA *) ((UINT8 *) ArpEntry + EntryLength); + } +} + + +/** + Notify function to handle the received ICMP message in DPC. + + @param Context The PXEBC private data. + +**/ +VOID +EFIAPI +PxeBcIcmpErrorDpcHandle ( + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_IP4_RECEIVE_DATA *RxData; + EFI_IP4_PROTOCOL *Ip4; + PXEBC_PRIVATE_DATA *Private; + EFI_PXE_BASE_CODE_MODE *Mode; + UINT8 Type; + UINTN Index; + UINT32 CopiedLen; + UINT8 *IcmpError; + + Private =3D (PXEBC_PRIVATE_DATA *) Context; + Mode =3D &Private->Mode; + Status =3D Private->IcmpToken.Status; + RxData =3D Private->IcmpToken.Packet.RxData; + Ip4 =3D Private->Ip4; + + ASSERT (!Mode->UsingIpv6); + + if (Status =3D=3D EFI_ABORTED) { + // + // It's triggered by user cancellation. + // + return; + } + + if (RxData =3D=3D NULL) { + goto ON_EXIT; + } + + if (Status !=3D EFI_ICMP_ERROR) { + // + // The return status should be recognized as EFI_ICMP_ERROR. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + if (EFI_IP4 (RxData->Header->SourceAddress) !=3D 0 && + !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) { + // + // The source address of the received packet should be a valid unicast= address. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationI= p.v4)) { + // + // The destination address of the received packet should be equal to t= he host address. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + if (RxData->Header->Protocol !=3D EFI_IP_PROTO_ICMP) { + // + // The protocol value in the header of the receveid packet should be E= FI_IP_PROTO_ICMP. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + Type =3D *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer); + + if (Type !=3D ICMP_DEST_UNREACHABLE && + Type !=3D ICMP_SOURCE_QUENCH && + Type !=3D ICMP_REDIRECT && + Type !=3D ICMP_TIME_EXCEEDED && + Type !=3D ICMP_PARAMETER_PROBLEM) { + // + // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + // + // Copy the right ICMP error message into mode data. + // + CopiedLen =3D 0; + IcmpError =3D (UINT8 *) &Mode->IcmpError; + + for (Index =3D 0; Index < RxData->FragmentCount; Index++) { + CopiedLen +=3D RxData->FragmentTable[Index].FragmentLength; + if (CopiedLen <=3D sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) { + CopyMem ( + IcmpError, + RxData->FragmentTable[Index].FragmentBuffer, + RxData->FragmentTable[Index].FragmentLength + ); + } else { + CopyMem ( + IcmpError, + RxData->FragmentTable[Index].FragmentBuffer, + CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR) + ); + } + IcmpError +=3D CopiedLen; + } + +ON_EXIT: + Private->IcmpToken.Status =3D EFI_NOT_READY; + Ip4->Receive (Ip4, &Private->IcmpToken); +} + + +/** + Callback function to update the latest ICMP6 error message. + + @param Event The event signalled. + @param Context The context passed in using the event noti= fier. + +**/ +VOID +EFIAPI +PxeBcIcmpErrorUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context); +} + + +/** + Notify function to handle the received ICMP6 message in DPC. + + @param Context The PXEBC private data. + +**/ +VOID +EFIAPI +PxeBcIcmp6ErrorDpcHandle ( + IN VOID *Context + ) +{ + PXEBC_PRIVATE_DATA *Private; + EFI_IP6_RECEIVE_DATA *RxData; + EFI_IP6_PROTOCOL *Ip6; + EFI_PXE_BASE_CODE_MODE *Mode; + EFI_STATUS Status; + UINTN Index; + UINT8 Type; + UINT32 CopiedLen; + UINT8 *Icmp6Error; + + Private =3D (PXEBC_PRIVATE_DATA *) Context; + Mode =3D &Private->Mode; + Status =3D Private->Icmp6Token.Status; + RxData =3D Private->Icmp6Token.Packet.RxData; + Ip6 =3D Private->Ip6; + + ASSERT (Mode->UsingIpv6); + + if (Status =3D=3D EFI_ABORTED) { + // + // It's triggered by user cancellation. + // + return; + } + + if (RxData =3D=3D NULL) { + goto ON_EXIT; + } + + if (Status !=3D EFI_ICMP_ERROR) { + // + // The return status should be recognized as EFI_ICMP_ERROR. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) { + // + // The source address of the received packet should be a valid unicast= address. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) && + !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationI= p.v6)) { + // + // The destination address of the received packet should be equal to t= he host address. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + if (RxData->Header->NextHeader !=3D IP6_ICMP) { + // + // The nextheader in the header of the receveid packet should be IP6_I= CMP. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + Type =3D *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer); + + if (Type !=3D ICMP_V6_DEST_UNREACHABLE && + Type !=3D ICMP_V6_PACKET_TOO_BIG && + Type !=3D ICMP_V6_PACKET_TOO_BIG && + Type !=3D ICMP_V6_PARAMETER_PROBLEM) { + // + // The type of the receveid packet should be an ICMP6 error message. + // + gBS->SignalEvent (RxData->RecycleSignal); + goto ON_EXIT; + } + + // + // Copy the right ICMP6 error message into mode data. + // + CopiedLen =3D 0; + Icmp6Error =3D (UINT8 *) &Mode->IcmpError; + + for (Index =3D 0; Index < RxData->FragmentCount; Index++) { + CopiedLen +=3D RxData->FragmentTable[Index].FragmentLength; + if (CopiedLen <=3D sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) { + CopyMem ( + Icmp6Error, + RxData->FragmentTable[Index].FragmentBuffer, + RxData->FragmentTable[Index].FragmentLength + ); + } else { + CopyMem ( + Icmp6Error, + RxData->FragmentTable[Index].FragmentBuffer, + CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR) + ); + } + Icmp6Error +=3D CopiedLen; + } + +ON_EXIT: + Private->Icmp6Token.Status =3D EFI_NOT_READY; + Ip6->Receive (Ip6, &Private->Icmp6Token); +} + + +/** + Callback function to update the latest ICMP6 error message. + + @param Event The event signalled. + @param Context The context passed in using the event noti= fier. + +**/ +VOID +EFIAPI +PxeBcIcmp6ErrorUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + QueueDpc (TPL_CALLBACK, PxeBcIcmp6ErrorDpcHandle, Context); +} + + +/** + This function is to configure a UDPv4 instance for UdpWrite. + + @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL. + @param[in] StationIp The pointer to the station address= . + @param[in] SubnetMask The pointer to the subnet mask. + @param[in] Gateway The pointer to the gateway address= . + @param[in, out] SrcPort The pointer to the source port. + @param[in] DoNotFragment If TRUE, fragment is not enabled. + Otherwise, fragment is enabled. + + @retval EFI_SUCCESS Successfully configured this insta= nce. + @retval Others Failed to configure this instance. + +**/ +EFI_STATUS +PxeBcConfigUdp4Write ( + IN EFI_UDP4_PROTOCOL *Udp4, + IN EFI_IPv4_ADDRESS *StationIp, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *Gateway, + IN OUT UINT16 *SrcPort, + IN BOOLEAN DoNotFragment + ) +{ + EFI_UDP4_CONFIG_DATA Udp4CfgData; + EFI_STATUS Status; + + ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData)); + + Udp4CfgData.TransmitTimeout =3D PXEBC_DEFAULT_LIFETIME; + Udp4CfgData.ReceiveTimeout =3D PXEBC_DEFAULT_LIFETIME; + Udp4CfgData.TypeOfService =3D DEFAULT_ToS; + Udp4CfgData.TimeToLive =3D DEFAULT_TTL; + Udp4CfgData.AllowDuplicatePort =3D TRUE; + Udp4CfgData.DoNotFragment =3D DoNotFragment; + + CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp)); + CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask)); + + Udp4CfgData.StationPort =3D *SrcPort; + + // + // Reset the UDPv4 instance. + // + Udp4->Configure (Udp4, NULL); + + Status =3D Udp4->Configure (Udp4, &Udp4CfgData); + if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) { + // + // The basic configuration is OK, need to add the default route entry + // + Status =3D Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Ga= teway); + if (EFI_ERROR (Status)) { + Udp4->Configure (Udp4, NULL); + } + } + + if (!EFI_ERROR (Status) && *SrcPort =3D=3D 0) { + Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL); + *SrcPort =3D Udp4CfgData.StationPort; + } + + return Status; +} + + +/** + This function is to configure a UDPv6 instance for UdpWrite. + + @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL. + @param[in] StationIp The pointer to the station address= . + @param[in, out] SrcPort The pointer to the source port. + + @retval EFI_SUCCESS Successfully configured this insta= nce. + @retval Others Failed to configure this instance. + +**/ +EFI_STATUS +PxeBcConfigUdp6Write ( + IN EFI_UDP6_PROTOCOL *Udp6, + IN EFI_IPv6_ADDRESS *StationIp, + IN OUT UINT16 *SrcPort + ) +{ + EFI_UDP6_CONFIG_DATA CfgData; + EFI_STATUS Status; + + ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA)); + + CfgData.ReceiveTimeout =3D PXEBC_DEFAULT_LIFETIME; + CfgData.TransmitTimeout =3D PXEBC_DEFAULT_LIFETIME; + CfgData.HopLimit =3D PXEBC_DEFAULT_HOPLIMIT; + CfgData.AllowDuplicatePort =3D TRUE; + CfgData.StationPort =3D *SrcPort; + + CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS)); + + // + // Reset the UDPv6 instance. + // + Udp6->Configure (Udp6, NULL); + + Status =3D Udp6->Configure (Udp6, &CfgData); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!EFI_ERROR (Status) && *SrcPort =3D=3D 0) { + Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL); + *SrcPort =3D CfgData.StationPort; + } + + return Status; +} + + +/** + This function is to configure a UDPv4 instance for UdpWrite. + + @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL. + @param[in] Session The pointer to the UDP4 session da= ta. + @param[in] TimeoutEvent The event for timeout. + @param[in] Gateway The pointer to the gateway address= . + @param[in] HeaderSize An optional field which may be set= to the length of a header + at HeaderPtr to be prefixed to the= data at BufferPtr. + @param[in] HeaderPtr If HeaderSize is not NULL, a point= er to a header to be + prefixed to the data at BufferPtr. + @param[in] BufferSize A pointer to the size of the data = at BufferPtr. + @param[in] BufferPtr A pointer to the data to be writte= n. + + @retval EFI_SUCCESS Successfully send out data using U= dp4Write. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp4Write ( + IN EFI_UDP4_PROTOCOL *Udp4, + IN EFI_UDP4_SESSION_DATA *Session, + IN EFI_EVENT TimeoutEvent, + IN EFI_IPv4_ADDRESS *Gateway OPTIONAL, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN UINTN *BufferSize, + IN VOID *BufferPtr + ) +{ + EFI_UDP4_COMPLETION_TOKEN Token; + EFI_UDP4_TRANSMIT_DATA *TxData; + UINT32 TxLength; + UINT32 FragCount; + UINT32 DataLength; + BOOLEAN IsDone; + EFI_STATUS Status; + + // + // Arrange one fragment buffer for data, and another fragment buffer for= header if has. + // + FragCount =3D (HeaderSize !=3D NULL) ? 2 : 1; + TxLength =3D sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof= (EFI_UDP4_FRAGMENT_DATA); + TxData =3D (EFI_UDP4_TRANSMIT_DATA *) AllocateZeroPool (TxLength); + if (TxData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TxData->FragmentCount =3D FragCount; + TxData->FragmentTable[FragCount - 1].FragmentLength =3D (UINT32) *Buffer= Size; + TxData->FragmentTable[FragCount - 1].FragmentBuffer =3D BufferPtr; + DataLength =3D (UINT32) *Buffer= Size; + + if (HeaderSize !=3D NULL) { + TxData->FragmentTable[0].FragmentLength =3D (UINT32) *HeaderSize; + TxData->FragmentTable[0].FragmentBuffer =3D HeaderPtr; + DataLength +=3D (UINT32) *HeaderSize; + } + + if (Gateway !=3D NULL) { + TxData->GatewayAddress =3D Gateway; + } + + TxData->UdpSessionData =3D Session; + TxData->DataLength =3D DataLength; + Token.Packet.TxData =3D TxData; + Token.Status =3D EFI_NOT_READY; + IsDone =3D FALSE; + + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &IsDone, + &Token.Event + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status =3D Udp4->Transmit (Udp4, &Token); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Poll the UDPv6 read instance if no packet received and no timeout tri= ggered. + // + while (!IsDone && + Token.Status =3D=3D EFI_NOT_READY && + EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + Udp4->Poll (Udp4); + } + + Status =3D (Token.Status =3D=3D EFI_NOT_READY) ? EFI_TIMEOUT : Token.Sta= tus; + +ON_EXIT: + if (Token.Event !=3D NULL) { + gBS->CloseEvent (Token.Event); + } + FreePool (TxData); + + return Status; +} + + +/** + This function is to configure a UDPv4 instance for UdpWrite. + + @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL. + @param[in] Session The pointer to the UDP6 session da= ta. + @param[in] TimeoutEvent The event for timeout. + @param[in] HeaderSize An optional field which may be set= to the length of a header + at HeaderPtr to be prefixed to the= data at BufferPtr. + @param[in] HeaderPtr If HeaderSize is not NULL, a point= er to a header to be + prefixed to the data at BufferPtr. + @param[in] BufferSize A pointer to the size of the data = at BufferPtr. + @param[in] BufferPtr A pointer to the data to be writte= n. + + @retval EFI_SUCCESS Successfully sent out data using U= dp6Write. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp6Write ( + IN EFI_UDP6_PROTOCOL *Udp6, + IN EFI_UDP6_SESSION_DATA *Session, + IN EFI_EVENT TimeoutEvent, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN UINTN *BufferSize, + IN VOID *BufferPtr + ) +{ + EFI_UDP6_COMPLETION_TOKEN Token; + EFI_UDP6_TRANSMIT_DATA *TxData; + UINT32 TxLength; + UINT32 FragCount; + UINT32 DataLength; + BOOLEAN IsDone; + EFI_STATUS Status; + + // + // Arrange one fragment buffer for data, and another fragment buffer for= header if has. + // + FragCount =3D (HeaderSize !=3D NULL) ? 2 : 1; + TxLength =3D sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof= (EFI_UDP6_FRAGMENT_DATA); + TxData =3D (EFI_UDP6_TRANSMIT_DATA *) AllocateZeroPool (TxLength); + if (TxData =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + TxData->FragmentCount =3D FragCount; + TxData->FragmentTable[FragCount - 1].FragmentLength =3D (UINT32) *Buffer= Size; + TxData->FragmentTable[FragCount - 1].FragmentBuffer =3D BufferPtr; + DataLength =3D (UINT32) *Buffer= Size; + + if (HeaderSize !=3D NULL) { + TxData->FragmentTable[0].FragmentLength =3D (UINT32) *HeaderSize; + TxData->FragmentTable[0].FragmentBuffer =3D HeaderPtr; + DataLength +=3D (UINT32) *HeaderSize; + } + + TxData->UdpSessionData =3D Session; + TxData->DataLength =3D DataLength; + Token.Packet.TxData =3D TxData; + Token.Status =3D EFI_NOT_READY; + IsDone =3D FALSE; + + Status =3D gBS->CreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + PxeBcCommonNotify, + &IsDone, + &Token.Event + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + Status =3D Udp6->Transmit (Udp6, &Token); + if (EFI_ERROR (Status)) { + goto ON_EXIT; + } + + // + // Poll the UDPv6 read instance if no packet received and no timeout tri= ggered. + // + while (!IsDone && + Token.Status =3D=3D EFI_NOT_READY && + EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + Udp6->Poll (Udp6); + } + + Status =3D (Token.Status =3D=3D EFI_NOT_READY) ? EFI_TIMEOUT : Token.Sta= tus; + +ON_EXIT: + if (Token.Event !=3D NULL) { + gBS->CloseEvent (Token.Event); + } + FreePool (TxData); + + return Status; +} + + +/** + Check the received packet using the Ip filter. + + @param[in] Mode The pointer to the mode data of PxeBc. + @param[in] Session The pointer to the current UDPv4 session= . + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Passed the Ip filter successfully. + @retval FALSE Failed to pass the Ip filter. + +**/ +BOOLEAN +PxeBcCheckByIpFilter ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN UINT16 OpFlags + ) +{ + EFI_IP_ADDRESS DestinationIp; + UINTN Index; + + if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) =3D=3D 0) { + return TRUE; + } + + if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != =3D 0) { + return TRUE; + } + + // + // Convert the destination address in session data to host order. + // + if (Mode->UsingIpv6) { + CopyMem ( + &DestinationIp, + &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + NTOHLLL (&DestinationIp.v6); + } else { + ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS)); + CopyMem ( + &DestinationIp, + &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress, + sizeof (EFI_IPv4_ADDRESS) + ); + EFI_NTOHL (DestinationIp); + } + + if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MU= LTICAST) !=3D 0 && + (IP4_IS_MULTICAST (DestinationIp.Addr[0]) || + IP6_IS_MULTICAST (&DestinationIp))) { + return TRUE; + } + + if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != =3D 0 && + IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0])) { + ASSERT (!Mode->UsingIpv6); + return TRUE; + } + + if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != =3D 0 && + (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) || + EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp))) { + // + // Matched if the dest address is equal to the station address. + // + return TRUE; + } + + for (Index =3D 0; Index < Mode->IpFilter.IpCnt; Index++) { + ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT); + if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) |= | + EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp)) = { + // + // Matched if the dest address is equal to any of address in the fil= ter list. + // + return TRUE; + } + } + + return FALSE; +} + + +/** + Filter the received packet using the destination Ip. + + @param[in] Mode The pointer to the mode data of PxeBc. + @param[in] Session The pointer to the current UDPv4 session= . + @param[in, out] DestIp The pointer to the destination Ip addres= s. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Passed the IPv4 filter successfully. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcCheckByDestIp ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT EFI_IP_ADDRESS *DestIp, + IN UINT16 OpFlags + ) +{ + if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) !=3D 0) { + // + // Copy the destination address from the received packet if accept any= . + // + if (DestIp !=3D NULL) { + if (Mode->UsingIpv6) { + CopyMem ( + DestIp, + &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + } else { + ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS)); + CopyMem ( + DestIp, + &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress, + sizeof (EFI_IPv4_ADDRESS) + ); + } + + } + return TRUE; + } else if (DestIp !=3D NULL && + (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->= DestinationAddress) || + EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->= DestinationAddress))) { + // + // The destination address in the received packet is matched if presen= t. + // + return TRUE; + } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)S= ession)->DestinationAddress) || + EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)S= ession)->DestinationAddress)) { + // + // The destination address in the received packet is equal to the host= address. + // + return TRUE; + } + + return FALSE; +} + + +/** + Check the received packet using the destination port. + + @param[in] Mode The pointer to the mode data of PxeBc. + @param[in] Session The pointer to the current UDPv4 session= . + @param[in, out] DestPort The pointer to the destination port. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Passed the IPv4 filter successfully. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcCheckByDestPort ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT UINT16 *DestPort, + IN UINT16 OpFlags + ) +{ + UINT16 Port; + + if (Mode->UsingIpv6) { + Port =3D ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort; + } else { + Port =3D ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort; + } + + if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) !=3D 0) { + // + // Return the destination port in the received packet if accept any. + // + if (DestPort !=3D NULL) { + *DestPort =3D Port; + } + return TRUE; + } else if (DestPort !=3D NULL && *DestPort =3D=3D Port) { + // + // The destination port in the received packet is matched if present. + // + return TRUE; + } + + return FALSE; +} + + +/** + Filter the received packet using the source Ip. + + @param[in] Mode The pointer to the mode data of PxeBc. + @param[in] Session The pointer to the current UDPv4 session= . + @param[in, out] SrcIp The pointer to the source Ip address. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Passed the IPv4 filter successfully. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcFilterBySrcIp ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT EFI_IP_ADDRESS *SrcIp, + IN UINT16 OpFlags + ) +{ + if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) !=3D 0) { + // + // Copy the source address from the received packet if accept any. + // + if (SrcIp !=3D NULL) { + if (Mode->UsingIpv6) { + CopyMem ( + SrcIp, + &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + } else { + ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS)); + CopyMem ( + SrcIp, + &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress, + sizeof (EFI_IPv4_ADDRESS) + ); + } + + } + return TRUE; + } else if (SrcIp !=3D NULL && + (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->S= ourceAddress) || + EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->S= ourceAddress))) { + // + // The source address in the received packet is matched if present. + // + return TRUE; + } + + return FALSE; +} + + +/** + Filter the received packet using the source port. + + @param[in] Mode The pointer to the mode data of PxeBc. + @param[in] Session The pointer to the current UDPv4 session= . + @param[in, out] SrcPort The pointer to the source port. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Passed the IPv4 filter successfully. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcFilterBySrcPort ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT UINT16 *SrcPort, + IN UINT16 OpFlags + ) +{ + UINT16 Port; + + if (Mode->UsingIpv6) { + Port =3D ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort; + } else { + Port =3D ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort; + } + + if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) !=3D 0) { + // + // Return the source port in the received packet if accept any. + // + if (SrcPort !=3D NULL) { + *SrcPort =3D Port; + } + return TRUE; + } else if (SrcPort !=3D NULL && *SrcPort =3D=3D Port) { + // + // The source port in the received packet is matched if present. + // + return TRUE; + } + + return FALSE; +} + + +/** + This function is to receive packet using Udp4Read. + + @param[in] Udp4 The pointer to EFI_UDP4_PROTOCOL. + @param[in] Token The pointer to EFI_UDP4_COMPLETION= _TOKEN. + @param[in] Mode The pointer to EFI_PXE_BASE_CODE_M= ODE. + @param[in] TimeoutEvent The event for timeout. + @param[in] OpFlags The UDP operation flags. + @param[in] IsDone The pointer to the IsDone flag. + @param[out] IsMatched The pointer to the IsMatched flag. + @param[in, out] DestIp The pointer to the destination add= ress. + @param[in, out] DestPort The pointer to the destination por= t. + @param[in, out] SrcIp The pointer to the source address. + @param[in, out] SrcPort The pointer to the source port. + + @retval EFI_SUCCESS Successfully read the data using U= dp4. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp4Read ( + IN EFI_UDP4_PROTOCOL *Udp4, + IN EFI_UDP4_COMPLETION_TOKEN *Token, + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN EFI_EVENT TimeoutEvent, + IN UINT16 OpFlags, + IN BOOLEAN *IsDone, + OUT BOOLEAN *IsMatched, + 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 + ) +{ + EFI_UDP4_RECEIVE_DATA *RxData; + EFI_UDP4_SESSION_DATA *Session; + EFI_STATUS Status; + + Token->Status =3D EFI_NOT_READY; + *IsDone =3D FALSE; + + Status =3D Udp4->Receive (Udp4, Token); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Poll the UDPv6 read instance if no packet received and no timeout tri= ggered. + // + while (!(*IsDone) && + Token->Status =3D=3D EFI_NOT_READY && + EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + // + // Poll the token utill reply/ICMPv6 error message received or timeout= . + // + Udp4->Poll (Udp4); + if (Token->Status =3D=3D EFI_ICMP_ERROR || + Token->Status =3D=3D EFI_NETWORK_UNREACHABLE || + Token->Status =3D=3D EFI_HOST_UNREACHABLE || + Token->Status =3D=3D EFI_PROTOCOL_UNREACHABLE || + Token->Status =3D=3D EFI_PORT_UNREACHABLE) { + break; + } + } + + Status =3D (Token->Status =3D=3D EFI_NOT_READY) ? EFI_TIMEOUT : Token->S= tatus; + + if (!EFI_ERROR (Status)) { + // + // check whether this packet matches the filters + // + RxData =3D Token->Packet.RxData; + Session =3D &RxData->UdpSession; + + *IsMatched =3D PxeBcCheckByIpFilter (Mode, Session, OpFlags); + + if (*IsMatched) { + *IsMatched =3D PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags); + } + + if (*IsMatched) { + *IsMatched =3D PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlag= s); + } + + if (*IsMatched) { + *IsMatched =3D PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags); + } + + if (*IsMatched) { + *IsMatched =3D PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags= ); + } + + if (!(*IsMatched)) { + // + // Recycle the receiving buffer if not matched. + // + gBS->SignalEvent (RxData->RecycleSignal); + } + } + + return Status; +} + + +/** + This function is to receive packets using Udp6Read. + + @param[in] Udp6 The pointer to EFI_UDP6_PROTOCOL. + @param[in] Token The pointer to EFI_UDP6_COMPLETION= _TOKEN. + @param[in] Mode The pointer to EFI_PXE_BASE_CODE_M= ODE. + @param[in] TimeoutEvent The event for timeout. + @param[in] OpFlags The UDP operation flags. + @param[in] IsDone The pointer to the IsDone flag. + @param[out] IsMatched The pointer to the IsMatched flag. + @param[in, out] DestIp The pointer to the destination add= ress. + @param[in, out] DestPort The pointer to the destination por= t. + @param[in, out] SrcIp The pointer to the source address. + @param[in, out] SrcPort The pointer to the source port. + + @retval EFI_SUCCESS Successfully read data using Udp6. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp6Read ( + IN EFI_UDP6_PROTOCOL *Udp6, + IN EFI_UDP6_COMPLETION_TOKEN *Token, + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN EFI_EVENT TimeoutEvent, + IN UINT16 OpFlags, + IN BOOLEAN *IsDone, + OUT BOOLEAN *IsMatched, + 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 + ) +{ + EFI_UDP6_RECEIVE_DATA *RxData; + EFI_UDP6_SESSION_DATA *Session; + EFI_STATUS Status; + + Token->Status =3D EFI_NOT_READY; + *IsDone =3D FALSE; + + Status =3D Udp6->Receive (Udp6, Token); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Poll the UDPv6 read instance if no packet received and no timeout tri= ggered. + // + while (!(*IsDone) && + Token->Status =3D=3D EFI_NOT_READY && + EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) { + // + // Poll the token utill reply/ICMPv6 error message received or timeout= . + // + Udp6->Poll (Udp6); + if (Token->Status =3D=3D EFI_ICMP_ERROR || + Token->Status =3D=3D EFI_NETWORK_UNREACHABLE || + Token->Status =3D=3D EFI_HOST_UNREACHABLE || + Token->Status =3D=3D EFI_PROTOCOL_UNREACHABLE || + Token->Status =3D=3D EFI_PORT_UNREACHABLE) { + break; + } + } + + Status =3D (Token->Status =3D=3D EFI_NOT_READY) ? EFI_TIMEOUT : Token->S= tatus; + + if (!EFI_ERROR (Status)) { + // + // check whether this packet matches the filters + // + RxData =3D Token->Packet.RxData; + Session =3D &RxData->UdpSession; + + *IsMatched =3D PxeBcCheckByIpFilter (Mode, Session, OpFlags); + + if (*IsMatched) { + *IsMatched =3D PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags); + } + + if (*IsMatched) { + *IsMatched =3D PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlag= s); + } + + if (*IsMatched) { + *IsMatched =3D PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags); + } + + if (*IsMatched) { + *IsMatched =3D PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags= ); + } + + if (!(*IsMatched)) { + // + // Recycle the receiving buffer if not matched. + // + gBS->SignalEvent (RxData->RecycleSignal); + } + } + + return Status; +} + + +/** + This function is to display the IPv4 address. + + @param[in] Ip The pointer to the IPv4 address. + +**/ +VOID +PxeBcShowIp4Addr ( + IN EFI_IPv4_ADDRESS *Ip + ) +{ + UINTN Index; + + for (Index =3D 0; Index < 4; Index++) { + AsciiPrint ("%d", Ip->Addr[Index]); + if (Index < 3) { + AsciiPrint ("."); + } + } +} + + +/** + This function is to display the IPv6 address. + + @param[in] Ip The pointer to the IPv6 address. + +**/ +VOID +PxeBcShowIp6Addr ( + IN EFI_IPv6_ADDRESS *Ip + ) +{ + UINTN Index; + + for (Index =3D 0; Index < 16; Index++) { + + if (Ip->Addr[Index] !=3D 0) { + AsciiPrint ("%x", Ip->Addr[Index]); + } + Index++; + if (Index > 15) { + return; + } + if (((Ip->Addr[Index] & 0xf0) =3D=3D 0) && (Ip->Addr[Index - 1] !=3D 0= )) { + AsciiPrint ("0"); + } + AsciiPrint ("%x", Ip->Addr[Index]); + if (Index < 15) { + AsciiPrint (":"); + } + } +} + + +/** + This function is to convert UINTN to ASCII string with the required form= atting. + + @param[in] Number Numeric value to be converted. + @param[in] Buffer The pointer to the buffer for ASCII string. + @param[in] Length The length of the required format. + +**/ +VOID +PxeBcUintnToAscDecWithFormat ( + IN UINTN Number, + IN UINT8 *Buffer, + IN INTN Length + ) +{ + UINTN Remainder; + + while (Length > 0) { + Length--; + Remainder =3D Number % 10; + Number /=3D 10; + Buffer[Length] =3D (UINT8) ('0' + Remainder); + } +} + + +/** + This function is to convert a UINTN to a ASCII string, and return the + actual length of the buffer. + + @param[in] Number Numeric value to be converted. + @param[in] Buffer The pointer to the buffer for ASCII string. + @param[in] BufferSize The maxsize of the buffer. + + @return Length The actual length of the ASCII string. + +**/ +UINTN +PxeBcUintnToAscDec ( + IN UINTN Number, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +{ + UINTN Index; + UINTN Length; + CHAR8 TempStr[64]; + + Index =3D 63; + TempStr[Index] =3D 0; + + do { + Index--; + TempStr[Index] =3D (CHAR8) ('0' + (Number % 10)); + Number =3D (UINTN) (Number / 10); + } while (Number !=3D 0); + + AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]); + + Length =3D AsciiStrLen ((CHAR8 *) Buffer); + + return Length; +} + + +/** + This function is to convert unicode hex number to a UINT8. + + @param[out] Digit The converted UINT8 for output. + @param[in] Char The unicode hex number to be conver= ted. + + @retval EFI_SUCCESS Successfully converted the unicode = hex. + @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex. + +**/ +EFI_STATUS +PxeBcUniHexToUint8 ( + OUT UINT8 *Digit, + IN CHAR16 Char + ) +{ + if ((Char >=3D L'0') && (Char <=3D L'9')) { + *Digit =3D (UINT8) (Char - L'0'); + return EFI_SUCCESS; + } + + if ((Char >=3D L'A') && (Char <=3D L'F')) { + *Digit =3D (UINT8) (Char - L'A' + 0x0A); + return EFI_SUCCESS; + } + + if ((Char >=3D L'a') && (Char <=3D L'f')) { + *Digit =3D (UINT8) (Char - L'a' + 0x0A); + return EFI_SUCCESS; + } + + return EFI_INVALID_PARAMETER; +} + +/** + Calculate the elapsed time. + + @param[in] Private The pointer to PXE private data + +**/ +VOID +CalcElapsedTime ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + EFI_TIME Time; + UINT64 CurrentStamp; + UINT64 ElapsedTimeValue; + + // + // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day= /month. + // + ZeroMem (&Time, sizeof (EFI_TIME)); + gRT->GetTime (&Time, NULL); + CurrentStamp =3D (UINT64) + ( + ((((((Time.Year - 1900) * 360 + + (Time.Month - 1)) * 30 + + (Time.Day - 1)) * 24 + Time.Hour) * 60 + + Time.Minute) * 60 + Time.Second) * 100 + + DivU64x32(Time.Nanosecond, 10000000) + ); + + // + // Sentinel value of 0 means that this is the first DHCP packet that we = are + // sending and that we need to initialize the value. First DHCP Solicit + // gets 0 elapsed-time. Otherwise, calculate based on StartTime. + // + if (Private->ElapsedTime =3D=3D 0) { + Private->ElapsedTime =3D CurrentStamp; + } else { + ElapsedTimeValue =3D CurrentStamp - Private->ElapsedTime; + + // + // If elapsed time cannot fit in two bytes, set it to 0xffff. + // + if (ElapsedTimeValue > 0xffff) { + ElapsedTimeValue =3D 0xffff; + } + // + // Save the elapsed time + // + Private->ElapsedTime =3D ElapsedTimeValue; + } +} + diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/PxeBcSupport.h b/Platform/BroxtonPlatformPkg/Common/SampleCode/Netw= orkPkg/UefiPxeBcDxe/PxeBcSupport.h new file mode 100644 index 0000000..deb55e6 --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /PxeBcSupport.h @@ -0,0 +1,515 @@ +/** @file + Support functions declaration for UefiPxeBc Driver. + + Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.
+ + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BS= D License + which accompanies this distribution. The full text of the license may b= e 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 IMP= LIED. + +**/ + +#ifndef __EFI_PXEBC_SUPPORT_H__ +#define __EFI_PXEBC_SUPPORT_H__ + + +#define ICMP_DEST_UNREACHABLE 3 +#define ICMP_SOURCE_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO_REQUEST 8 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETER_PROBLEM 12 + + + +/** + Flush the previous configration using the new station Ip address. + + @param[in] Private Pointer to PxeBc private data. + @param[in] StationIp Pointer to the station Ip address. + @param[in] SubnetMask Pointer to the subnet mask address for v4. + + @retval EFI_SUCCESS Successfully flushed the previous config. + @retval Others Failed to flush using the new station Ip. + +**/ +EFI_STATUS +PxeBcFlushStationIp ( + PXEBC_PRIVATE_DATA *Private, + EFI_IP_ADDRESS *StationIp, + EFI_IP_ADDRESS *SubnetMask OPTIONAL + ); + + +/** + Notify callback function when an event is triggered. + + @param[in] Event The triggered event. + @param[in] Context The opaque parameter to the function. + +**/ +VOID +EFIAPI +PxeBcCommonNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +/** + Perform arp resolution from the arp cache in PxeBcMode. + + @param Mode Pointer to EFI_PXE_BASE_CODE_MODE. + @param Ip4Addr The Ip4 address for resolution. + @param MacAddress The resoluted MAC address if the resolution is su= ccessful. + The value is undefined if resolution fails. + + @retval TRUE Found a matched entry. + @retval FALSE Did not find a matched entry. + +**/ +BOOLEAN +PxeBcCheckArpCache ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN EFI_IPv4_ADDRESS *Ip4Addr, + OUT EFI_MAC_ADDRESS *MacAddress + ); + + +/** + Update arp cache periodically. + + @param Event Pointer to EFI_PXE_BC_PROTOCOL. + @param Context Context of the timer event. + +**/ +VOID +EFIAPI +PxeBcArpCacheUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +/** + xxx + + @param Event The event signaled. + @param Context The context passed in by the event notifie= r. + +**/ +VOID +EFIAPI +PxeBcIcmpErrorUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +/** + xxx + + @param Event The event signaled. + @param Context The context passed in by the event notifie= r. + +**/ +VOID +EFIAPI +PxeBcIcmp6ErrorUpdate ( + IN EFI_EVENT Event, + IN VOID *Context + ); + + +/** + This function is to configure a UDPv4 instance for UdpWrite. + + @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL. + @param[in] StationIp Pointer to the station address. + @param[in] SubnetMask Pointer to the subnet mask. + @param[in] Gateway Pointer to the gateway address. + @param[in, out] SrcPort Pointer to the source port. + @param[in] DoNotFragment The flag of DoNotFragment bit in t= he IPv4 + packet. + + @retval EFI_SUCCESS Successfully configured this insta= nce. + @retval Others Failed to configure this instance. + +**/ +EFI_STATUS +PxeBcConfigUdp4Write ( + IN EFI_UDP4_PROTOCOL *Udp4, + IN EFI_IPv4_ADDRESS *StationIp, + IN EFI_IPv4_ADDRESS *SubnetMask, + IN EFI_IPv4_ADDRESS *Gateway, + IN OUT UINT16 *SrcPort, + IN BOOLEAN DoNotFragment + ); + + +/** + This function is to configure a UDPv6 instance for UdpWrite. + + @param[in] Udp6 Pointer to EFI_UDP6_PROTOCOL. + @param[in] StationIp Pointer to the station address. + @param[in, out] SrcPort Pointer to the source port. + + @retval EFI_SUCCESS Successfuly configured this instan= ce. + @retval Others Failed to configure this instance. + +**/ +EFI_STATUS +PxeBcConfigUdp6Write ( + IN EFI_UDP6_PROTOCOL *Udp6, + IN EFI_IPv6_ADDRESS *StationIp, + IN OUT UINT16 *SrcPort + ); + +/** + This function is to configure a UDPv4 instance for UdpWrite. + + @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL. + @param[in] Session Pointer to the UDP4 session data. + @param[in] TimeoutEvent The event for timeout. + @param[in] Gateway Pointer to the gateway address. + @param[in] HeaderSize An optional field which may be set= to the length of a header + at HeaderPtr to be prefixed to the= data at BufferPtr. + @param[in] HeaderPtr If HeaderSize is not NULL, a point= er to a header to be + prefixed to the data at BufferPtr. + @param[in] BufferSize A pointer to the size of the data = at BufferPtr. + @param[in] BufferPtr A pointer to the data to be writte= n. + + @retval EFI_SUCCESS Successfully sent out data with Ud= p4Write. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp4Write ( + IN EFI_UDP4_PROTOCOL *Udp4, + IN EFI_UDP4_SESSION_DATA *Session, + IN EFI_EVENT TimeoutEvent, + IN EFI_IPv4_ADDRESS *Gateway OPTIONAL, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN UINTN *BufferSize, + IN VOID *BufferPtr + ); + + +/** + This function is to configure a UDPv6 instance for UdpWrite. + + @param[in] Udp6 Pointer to EFI_UDP6_PROTOCOL. + @param[in] Session Pointer to the UDP6 session data. + @param[in] TimeoutEvent The event for timeout. + @param[in] HeaderSize An optional field which may be set= to the length of a header + at HeaderPtr to be prefixed to the= data at BufferPtr. + @param[in] HeaderPtr If HeaderSize is not NULL, a point= er to a header to be + prefixed to the data at BufferPtr. + @param[in] BufferSize A pointer to the size of the data = at BufferPtr. + @param[in] BufferPtr A pointer to the data to be writte= n. + + @retval EFI_SUCCESS Successfully to send out data with= Udp6Write. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp6Write ( + IN EFI_UDP6_PROTOCOL *Udp6, + IN EFI_UDP6_SESSION_DATA *Session, + IN EFI_EVENT TimeoutEvent, + IN UINTN *HeaderSize OPTIONAL, + IN VOID *HeaderPtr OPTIONAL, + IN UINTN *BufferSize, + IN VOID *BufferPtr + ); + + +/** + Check the received packet with the Ip filter. + + @param[in] Mode Pointer to mode data of PxeBc. + @param[in] Session Pointer to the current UDPv4 session. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Succesfully passed the Ip filter. + @retval FALSE Failed to pass the Ip filter. + +**/ +BOOLEAN +PxeBcCheckByIpFilter ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN UINT16 OpFlags + ); + + +/** + Filter the received packet with the destination Ip. + + @param[in] Mode Pointer to mode data of PxeBc. + @param[in] Session Pointer to the current UDPv4 session. + @param[in, out] DestIp Pointer to the dest Ip address. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Succesfully passed the IPv4 filter. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcCheckByDestIp ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT EFI_IP_ADDRESS *DestIp, + IN UINT16 OpFlags + ); + + +/** + Check the received packet with the destination port. + + @param[in] Mode Pointer to mode data of PxeBc. + @param[in] Session Pointer to the current UDPv4 session. + @param[in, out] DestPort Pointer to the destination port. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Succesfully passed the IPv4 filter. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcCheckByDestPort ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT UINT16 *DestPort, + IN UINT16 OpFlags + ); + + +/** + Filter the received packet with the source Ip. + + @param[in] Mode Pointer to mode data of PxeBc. + @param[in] Session Pointer to the current UDPv4 session. + @param[in, out] SrcIp Pointer to the source Ip address. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Succesfully passed the IPv4 filter. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcFilterBySrcIp ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT EFI_IP_ADDRESS *SrcIp, + IN UINT16 OpFlags + ); + + +/** + Filter the received packet with the source port. + + @param[in] Mode Pointer to mode data of PxeBc. + @param[in] Session Pointer to the current UDPv4 session. + @param[in, out] SrcPort Pointer to the source port. + @param[in] OpFlags Operation flag for UdpRead/UdpWrite. + + @retval TRUE Succesfully passed the IPv4 filter. + @retval FALSE Failed to pass the IPv4 filter. + +**/ +BOOLEAN +PxeBcFilterBySrcPort ( + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN VOID *Session, + IN OUT UINT16 *SrcPort, + IN UINT16 OpFlags + ); + + +/** + This function is to receive packet with Udp4Read. + + @param[in] Udp4 Pointer to EFI_UDP4_PROTOCOL. + @param[in] Token Pointer to EFI_UDP4_COMPLETION_TOK= EN. + @param[in] Mode Pointer to EFI_PXE_BASE_CODE_MODE. + @param[in] TimeoutEvent The event for timeout. + @param[in] OpFlags The UDP operation flags. + @param[in] IsDone Pointer to IsDone flag. + @param[out] IsMatched Pointer to IsMatched flag. + @param[in, out] DestIp Pointer to destination address. + @param[in, out] DestPort Pointer to destination port. + @param[in, out] SrcIp Pointer to source address. + @param[in, out] SrcPort Pointer to source port. + + @retval EFI_SUCCESS Successfully read data with Udp4. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp4Read ( + IN EFI_UDP4_PROTOCOL *Udp4, + IN EFI_UDP4_COMPLETION_TOKEN *Token, + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN EFI_EVENT TimeoutEvent, + IN UINT16 OpFlags, + IN BOOLEAN *IsDone, + OUT BOOLEAN *IsMatched, + 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 + ); + + +/** + This function is to receive packet with Udp6Read. + + @param[in] Udp6 Pointer to EFI_UDP6_PROTOCOL. + @param[in] Token Pointer to EFI_UDP6_COMPLETION_TOK= EN. + @param[in] Mode Pointer to EFI_PXE_BASE_CODE_MODE. + @param[in] TimeoutEvent The event for timeout. + @param[in] OpFlags The UDP operation flags. + @param[in] IsDone Pointer to IsDone flag. + @param[out] IsMatched Pointer to IsMatched flag. + @param[in, out] DestIp Pointer to destination address. + @param[in, out] DestPort Pointer to destination port. + @param[in, out] SrcIp Pointer to source address. + @param[in, out] SrcPort Pointer to source port. + + @retval EFI_SUCCESS Successfully read data with Udp6. + @retval Others Failed to send out data. + +**/ +EFI_STATUS +PxeBcUdp6Read ( + IN EFI_UDP6_PROTOCOL *Udp6, + IN EFI_UDP6_COMPLETION_TOKEN *Token, + IN EFI_PXE_BASE_CODE_MODE *Mode, + IN EFI_EVENT TimeoutEvent, + IN UINT16 OpFlags, + IN BOOLEAN *IsDone, + OUT BOOLEAN *IsMatched, + 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 + ); + + +/** + This function is to display the IPv4 address. + + @param[in] Ip Pointer to the IPv4 address. + +**/ +VOID +PxeBcShowIp4Addr ( + IN EFI_IPv4_ADDRESS *Ip + ); + + +/** + This function is to display the IPv6 address. + + @param[in] Ip Pointer to the IPv6 address. + +**/ +VOID +PxeBcShowIp6Addr ( + IN EFI_IPv6_ADDRESS *Ip + ); + + +/** + This function is to convert UINTN to ASCII string with required format. + + @param[in] Number Numeric value to be converted. + @param[in] Buffer Pointer to the buffer for ASCII string. + @param[in] Length Length of the required format. + +**/ +VOID +PxeBcUintnToAscDecWithFormat ( + IN UINTN Number, + IN UINT8 *Buffer, + IN INTN Length + ); + + +/** + This function is to convert a UINTN to a ASCII string, and return the + actual length of the buffer. + + @param[in] Number Numeric value to be converted. + @param[in] Buffer Pointer to the buffer for ASCII string. + @param[in] BufferSize The maxsize of the buffer. + =20 + @return Length The actual length of the ASCII string. + +**/ +UINTN +PxeBcUintnToAscDec ( + IN UINTN Number, + IN UINT8 *Buffer, + IN UINTN BufferSize + ); + +/** + This function is to convert unicode hex number to a UINT8. + + @param[out] Digit The converted UINT8 for output. + @param[in] Char The unicode hex number to be conver= ted. + + @retval EFI_SUCCESS Successfully converted the unicode = hex. + @retval EFI_INVALID_PARAMETER Failed to convert the unicode hex. + +**/ +EFI_STATUS +PxeBcUniHexToUint8 ( + OUT UINT8 *Digit, + IN CHAR16 Char + ); + +/** + Calculate the elapsed time. + + @param[in] Private The pointer to PXE private data + +**/ +VOID +CalcElapsedTime ( + IN PXEBC_PRIVATE_DATA *Private + ); + +/** + Get the Nic handle using any child handle in the IPv4 stack. + + @param[in] ControllerHandle Pointer to child handle over IPv4. + + @return NicHandle The pointer to the Nic handle. + +**/ +EFI_HANDLE +PxeBcGetNicByIp4Children ( + IN EFI_HANDLE ControllerHandle + ); + +/** + Get the Nic handle using any child handle in the IPv6 stack. + + @param[in] ControllerHandle Pointer to child handle over IPv6. + + @return NicHandle The pointer to the Nic handle. + +**/ +EFI_HANDLE +PxeBcGetNicByIp6Children ( + IN EFI_HANDLE ControllerHandle + ); +#endif diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/UefiPxeBcDxe.inf b/Platform/BroxtonPlatformPkg/Common/SampleCode/Ne= tworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf new file mode 100644 index 0000000..b6bd49f --- /dev/null +++ b/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiPxeBcDxe= /UefiPxeBcDxe.inf @@ -0,0 +1,109 @@ +## @file +# Access PXE-compatible devices for network access and network booting. +# =20 +# This driver provides PXE Base Code Protocol which is used to accessing +# PXE-compatible device for network access or booting. It could work toge= ther +# with an IPv4 stack, an IPv6 stack or both. +# +# +# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.
+# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the B= SD License +# which accompanies this distribution. The full text of the license may b= e 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 IM= PLIED. +# +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D UefiPxeBcDxe + FILE_GUID =3D B95E9FDA-26DE-48d2-8807-1F9107AC5E3A + MODULE_TYPE =3D UEFI_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D PxeBcDriverEntryPoint + UNLOAD_IMAGE =3D NetLibDefaultUnload + MODULE_UNI_FILE =3D UefiPxeBcDxe.uni + +# +# The following information is for reference only and not required by the = build tools. +# +# VALID_ARCHITECTURES =3D IA32 X64 IPF +# + +[Sources] + ComponentName.c + PxeBcDriver.c + PxeBcDriver.h + PxeBcImpl.c + PxeBcImpl.h + PxeBcBoot.c + PxeBcBoot.h + PxeBcDhcp6.c + PxeBcDhcp6.h + PxeBcDhcp4.c + PxeBcDhcp4.h + PxeBcMtftp.c + PxeBcMtftp.h + PxeBcSupport.c + PxeBcSupport.h + + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + + +[LibraryClasses] + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + BaseMemoryLib + MemoryAllocationLib + DebugLib + NetLib + DpcLib + DevicePathLib + PcdLib + +[Protocols] + ## TO_START + ## SOMETIMES_CONSUMES + gEfiDevicePathProtocolGuid =20 + gEfiNetworkInterfaceIdentifierProtocolGuid_31 ## SOMETIMES_CONSUM= ES + gEfiArpServiceBindingProtocolGuid ## TO_START + gEfiArpProtocolGuid ## TO_START + gEfiIp4ServiceBindingProtocolGuid ## TO_START + gEfiIp4ProtocolGuid ## TO_START + gEfiIp4Config2ProtocolGuid ## TO_START + gEfiIp6ServiceBindingProtocolGuid ## TO_START + gEfiIp6ProtocolGuid ## TO_START + gEfiIp6ConfigProtocolGuid ## TO_START + gEfiUdp4ServiceBindingProtocolGuid ## TO_START + gEfiUdp4ProtocolGuid ## TO_START + gEfiMtftp4ServiceBindingProtocolGuid ## TO_START + gEfiMtftp4ProtocolGuid ## TO_START + gEfiDhcp4ServiceBindingProtocolGuid ## TO_START + gEfiDhcp4ProtocolGuid ## TO_START + gEfiUdp6ServiceBindingProtocolGuid ## TO_START + gEfiUdp6ProtocolGuid ## TO_START + gEfiMtftp6ServiceBindingProtocolGuid ## TO_START + gEfiMtftp6ProtocolGuid ## TO_START + gEfiDhcp6ServiceBindingProtocolGuid ## TO_START + gEfiDhcp6ProtocolGuid ## TO_START + gEfiPxeBaseCodeCallbackProtocolGuid ## SOMETIMES_PRODUC= ES + gEfiPxeBaseCodeProtocolGuid ## BY_START + gEfiLoadFileProtocolGuid ## BY_START + gEfiAdapterInformationProtocolGuid ## SOMETIMES_CONSUM= ES + +[Guids] + gEfiAdapterInfoUndiIpv6SupportGuid ## SOMETIMES_CONSUM= ES ## GUID + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdTftpBlockSize ## SOMETIMES_CONSUM= ES +[UserExtensions.TianoCore."ExtraFiles"] + UefiPxeBcDxeExtra.uni diff --git a/Platform/BroxtonPlatformPkg/Common/SampleCode/NetworkPkg/UefiP= xeBcDxe/UefiPxeBcDxe.uni b/Platform/BroxtonPlatformPkg/Common/SampleCode/Ne= tworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.uni new file mode 100644 index 0000000000000000000000000000000000000000..37ca0cb0362e12966bc4df850eb= 5b1450601f811 GIT binary patch literal 2416 zcmd6oUuzRV6vgke;CC3>7nL?q5d{%3wW}^_Q__^`lO#=3D=3DEKRZ{*=3D_BYSAS3Ite#GVMjh$I$6C2unyN6YCEj#5J+Jej3p?$H$cCq9( zwF~Q6!HT|L<7|N6CF9`lK+A2;su}jeuKehnac>Q?$Nb<1uRi{{$Di5A8a1cLt!rbV ziPwNQ8L@{x-UZLxGZCZ6+u0tm7ucM=3D#Y3~oN!|swvYKGI^0=3Dow-4eg_tHe@%>ltM5 zAJy#sMx)y*6ja>Q!&wR&=3DUJEV7Q3jic#g=3DgAPcDyRl6c5S(U|%XNm%s_KdFucGc$G zb~a|8ugyBJRaY?*(oMCIz87|lUj~mce$F0%{gC%ld(8EMuifS73Go#(g;4=3DtRY3@I zF!T(4mNVO6rp3HGBDQKgXPs(0_kA$H^A+{(*y}p?s6p(U&?_S!V+u;ujX}4n(p9(5 z$SBm?(f?wlco|<4Vn_U*XXCJj-7u^Br^46j(0@Jn_VAnVtaegKrka(?6_XHa3Q}aL zj+Lh>n)z?d=3DIp$v(3Dw0jt_+dKW(HzLj-c)kUgmN1b60 z6%yy~_-t}o*Cl9qjaPrUJ_jM33eq@oRUZ}f#7loVsl$f&Ey%cpk+eR;R^Fge~qfICcKOXpwXD>~K zs?69P&+(aKcmMwBSjQrMFZhe>qg`2MYg^h=3DdqPxaQ#?gSc8}Gwx%J(O?9_6+l>E$o zbG9J++;&#r-`dKy_$ij+pUA!CZ0T!-UhUz0V|%~5vTHIUdj|S*_Sg2(UfCP0liGW0 z$Jj}UxyDw7!ZyC9+|RsXo0BdKl_6dMTg(c$Z21*-=3DiJ-&p4W}-L;d!K-2_INzh^^! z4obnxZa}Htwmwy{`rF*=3D(ZfFe=3D>eC9>o3=3D0&MJ0?ug%~f zL~#gusn!->ub#p4VPB-G*k2J39TMkzavpO!)Fo)SCu>&T&r1cwX!k%@&C!ldyz^Pk zv4XbBFI?$1uP^9l=3DaKeXA~TpTn7PC1ZBVZHwd*>KHWT}5F}z01(a^rIcI^y5LDL9T zwNHp9OxhGHcBQ8_V2_DM!~#Oog@nnD$vAi9A(kduYl~gDLT$14+?RJ;bBpXd=3DRzHN zMfqJSiP?a70;({EUVV%w?ux1Age>K#YRLLbu5SKd|Hg@!>pw9rtAtm?c2VOr=3Dm}bk zm@C!n|5rbKg*wh%njY1Yqpyj+Ez<6?RCff*xPHMU*h5gK;K$?)V0nfWIoc6D)c?SW gzNf63I!(d}`QoQ)E$r~6Q~xgfZr}G-%}9Cw09297Y5)KL literal 0 HcmV?d00001 diff --git a/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc b/Platf= orm/BroxtonPlatformPkg/PlatformDsc/Components.dsc index 0d2d0db..53658cf 100644 --- a/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc +++ b/Platform/BroxtonPlatformPkg/PlatformDsc/Components.dsc @@ -1,7 +1,7 @@ ## @file # Platform Components Description. # -# Copyright (c) 2016, Intel Corporation. All rights reserved.
+# Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the B= SD License @@ -325,7 +325,7 @@ NetworkPkg/Mtftp6Dxe/Mtftp6Dxe.inf !endif !if $(NETWORK_IP6_ENABLE) =3D=3D TRUE - NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf + $(PLATFORM_PACKAGE_COMMON)/SampleCode/NetworkPkg/UefiPxeBcDxe/UefiPxe= BcDxe.inf !else MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf { diff --git a/Platform/BroxtonPlatformPkg/PlatformPkg.fdf b/Platform/Broxton= PlatformPkg/PlatformPkg.fdf index 93f0422..0d9a087 100644 --- a/Platform/BroxtonPlatformPkg/PlatformPkg.fdf +++ b/Platform/BroxtonPlatformPkg/PlatformPkg.fdf @@ -1,7 +1,7 @@ ## @file # FDF file of Platform. # -# Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.
+# Copyright (c) 2008 - 2017, Intel Corporation. All rights reserved.
# # This program and the accompanying materials # are licensed and made available under the terms and conditions of the B= SD License @@ -681,7 +681,7 @@ APRIORI DXE { !endif !if $(NETWORK_IP6_ENABLE) =3D=3D TRUE INF NetworkPkg/TcpDxe/TcpDxe.inf - INF NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf + INF $(PLATFORM_PACKAGE_COMMON)/SampleCode/NetworkPkg/UefiPxeBcDxe/UefiPx= eBcDxe.inf !else INF MdeModulePkg/Universal/Network/UefiPxeBcDxe/UefiPxeBcDxe.inf INF MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Dxe.inf diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcM= ediaDeviceDxe/MMCSDBlockIo.c b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster= /Sdio/Dxe/MMC/MmcMediaDeviceDxe/MMCSDBlockIo.c index f89911c..5c91190 100644 --- a/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDev= iceDxe/MMCSDBlockIo.c +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/SouthCluster/Sdio/Dxe/MMC/MmcMediaDev= iceDxe/MMCSDBlockIo.c @@ -1,7 +1,7 @@ /** @file Block I/O protocol for MMC/SD device. =20 - Copyright (c) 2012 - 2016, Intel Corporation. All rights reserved.
+ Copyright (c) 2012 - 2017, Intel Corporation. All rights reserved.
=20 This program and the accompanying materials are licensed and made available under the terms and conditions of the BS= D License @@ -585,7 +585,8 @@ MMCSDBlockIoInit ( GP_CHUNK_SIZE =3D 0; if (((ExtCsd->PARTITIONING_SUPPORT & BIT0) =3D=3D BIT0) && ((ExtCsd->PARTITION_SETTING_COMPLETED & BIT0) =3D=3D BIT0)) { - GP_CHUNK_SIZE =3D MultU64x32 (ExtCsd->HC_WP_GRP_SIZE * ExtCsd->HC_ERAS= E_GRP_SIZE, SIZE_512KB); + GP_CHUNK_SIZE =3D MultU64x32 (ExtCsd->HC_WP_GRP_SIZE, ExtCsd->HC_ERASE= _GRP_SIZE); + GP_CHUNK_SIZE =3D MultU64x32 (GP_CHUNK_SIZE, SIZE_512KB); } =20 for (Loop =3D 0; Loop < MAX_NUMBER_OF_PARTITIONS; Partition++, Loop++) { --=20 2.7.0.windows.1