Reviewed-by: Fu Siyuan <siyuan...@intel.com>
> -----Original Message----- > From: Zhang, Lubo > Sent: Friday, October 14, 2016 3:28 PM > To: edk2-devel@lists.01.org > Cc: Ye, Ting <ting...@intel.com>; Fu, Siyuan <siyuan...@intel.com>; Wu, > Jiaxin <jiaxin...@intel.com> > Subject: [patch] NetworkPkg: Add dns support for pxe boot based on IPv6. > > The BootFileURL option (59) in dhcpv6 is used to deliver > the next server address with bootfile name, as an example > "tftp://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]/BOOTFILE_NAME; > mode=octet", it can also be “tftp://domain_name/BOOTFILE_NAME; > mode=octet”, this patch is to support this case. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Zhang Lubo <lubo.zh...@intel.com> > Cc: Ye Ting <ting...@intel.com> > Cc: Fu Siyuan <siyuan...@intel.com> > Cc: Wu Jiaxin <jiaxin...@intel.com> > --- > NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c | 18 ++- > NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 269 > +++++++++++++++++++++++++++---- > NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 5 +- > NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h | 3 + > NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf | 4 +- > 5 files changed, 261 insertions(+), 38 deletions(-) > > diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c > b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c > index 8eff13c..fc50a82 100644 > --- a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c > +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c > @@ -619,31 +619,33 @@ PxeBcDhcp6BootInfo ( > } > > ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); > > // > + // Set the station address to IP layer. > + // > + Status = PxeBcSetIp6Address (Private); > + if (EFI_ERROR (Status)) { > + return Status; > + } > + > + > + // > // Parse (m)tftp server ip address and bootfile name. > // > Status = PxeBcExtractBootFileUrl ( > + Private, > &Private->BootFileName, > &Private->ServerIp.v6, > (CHAR8 *) (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]- > >Data), > NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen) > ); > if (EFI_ERROR (Status)) { > return Status; > } > > // > - // Set the station address to IP layer. > - // > - Status = PxeBcSetIp6Address (Private); > - if (EFI_ERROR (Status)) { > - return Status; > - } > - > - // > // Parse the value of boot file size. > // > if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] != NULL) { > // > // Parse it out if have the boot file parameter option. > diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c > b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c > index 41d3d30..45377e3 100644 > --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c > +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c > @@ -91,14 +91,15 @@ PxeBcBuildDhcp6Options ( > > // > // Append client option request option > // > OptList[Index]->OpCode = HTONS (DHCP6_OPT_ORO); > - OptList[Index]->OpLen = HTONS (4); > + OptList[Index]->OpLen = HTONS (6); > OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]- > >Data; > OptEnt.Oro->OpCode[0] = HTONS(DHCP6_OPT_BOOT_FILE_URL); > OptEnt.Oro->OpCode[1] = HTONS(DHCP6_OPT_BOOT_FILE_PARAM); > + OptEnt.Oro->OpCode[2] = HTONS(DHCP6_OPT_DNS_SERVERS); > Index++; > OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]); > > // > // Append client network device interface option > @@ -214,14 +215,177 @@ PxeBcFreeBootFileOption ( > RemoveEntryList (Entry); > FreePool (Node); > } > } > > +/** > + Retrieve the boot server address using the EFI_DNS6_PROTOCOL. > + > + @param[in] Private Pointer to PxeBc private data. > + @param[in] HostName Pointer to buffer containing hostname. > + @param[out] IpAddress On output, pointer to buffer containing > IPv6 address. > + > + @retval EFI_SUCCESS Operation succeeded. > + @retval EFI_OUT_OF_RESOURCES Failed to allocate needed resources. > + @retval EFI_DEVICE_ERROR An unexpected network error occurred. > + @retval Others Other errors as indicated. > + > +**/ > +EFI_STATUS > +PxeBcDns6 ( > + IN PXEBC_PRIVATE_DATA *Private, > + IN CHAR16 *HostName, > + OUT EFI_IPv6_ADDRESS *IpAddress > + ) > +{ > + EFI_STATUS Status; > + EFI_DNS6_PROTOCOL *Dns6; > + EFI_DNS6_CONFIG_DATA Dns6ConfigData; > + EFI_DNS6_COMPLETION_TOKEN Token; > + EFI_HANDLE Dns6Handle; > + EFI_IPv6_ADDRESS *DnsServerList; > + BOOLEAN IsDone; > + > + Dns6 = NULL; > + Dns6Handle = NULL; > + DnsServerList = Private->DnsServer; > + ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN)); > + > + // > + // Create a DNSv6 child instance and get the protocol. > + // > + Status = NetLibCreateServiceChild ( > + Private->Controller, > + Private->Image, > + &gEfiDns6ServiceBindingProtocolGuid, > + &Dns6Handle > + ); > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + Status = gBS->OpenProtocol ( > + Dns6Handle, > + &gEfiDns6ProtocolGuid, > + (VOID **) &Dns6, > + Private->Image, > + Private->Controller, > + EFI_OPEN_PROTOCOL_BY_DRIVER > + ); > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + // > + // Configure DNS6 instance for the DNS server address and protocol. > + // > + ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA)); > + Dns6ConfigData.DnsServerCount = 1; > + Dns6ConfigData.DnsServerList = DnsServerList; > + Dns6ConfigData.EnableDnsCache = TRUE; > + Dns6ConfigData.Protocol = EFI_IP_PROTO_UDP; > + IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &Private->TmpStationIp.v6); > + Status = Dns6->Configure ( > + Dns6, > + &Dns6ConfigData > + ); > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + Token.Status = EFI_NOT_READY; > + IsDone = FALSE; > + // > + // Create event to set the IsDone flag when name resolution is > finished. > + // > + Status = gBS->CreateEvent ( > + EVT_NOTIFY_SIGNAL, > + TPL_NOTIFY, > + PxeBcCommonNotify, > + &IsDone, > + &Token.Event > + ); > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + // > + // Start asynchronous name resolution. > + // > + Status = Dns6->HostNameToIp (Dns6, HostName, &Token); > + if (EFI_ERROR (Status)) { > + goto Exit; > + } > + > + while (!IsDone) { > + Dns6->Poll (Dns6); > + } > + > + // > + // Name resolution is done, check result. > + // > + Status = Token.Status; > + if (!EFI_ERROR (Status)) { > + if (Token.RspData.H2AData == NULL) { > + Status = EFI_DEVICE_ERROR; > + goto Exit; > + } > + if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData- > >IpList == NULL) { > + Status = EFI_DEVICE_ERROR; > + goto Exit; > + } > + // > + // We just return the first IPv6 address from DNS protocol. > + // > + IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList); > + Status = EFI_SUCCESS; > + } > + > +Exit: > + FreePool (HostName); > + > + if (Token.Event != NULL) { > + gBS->CloseEvent (Token.Event); > + } > + if (Token.RspData.H2AData != NULL) { > + if (Token.RspData.H2AData->IpList != NULL) { > + FreePool (Token.RspData.H2AData->IpList); > + } > + FreePool (Token.RspData.H2AData); > + } > + > + if (Dns6 != NULL) { > + Dns6->Configure (Dns6, NULL); > + > + gBS->CloseProtocol ( > + Dns6Handle, > + &gEfiDns6ProtocolGuid, > + Private->Image, > + Private->Controller > + ); > + } > + > + if (Dns6Handle != NULL) { > + NetLibDestroyServiceChild ( > + Private->Controller, > + Private->Image, > + &gEfiDns6ServiceBindingProtocolGuid, > + Dns6Handle > + ); > + } > + > + if (DnsServerList != NULL) { > + FreePool (DnsServerList); > + } > + > + return Status; > +} > > /** > Parse the Boot File URL option. > > + @param[in] Private Pointer to PxeBc private data. > @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 > data. > @param[in] Length The length of the boot file URL option > data. > > @@ -230,10 +394,11 @@ PxeBcFreeBootFileOption ( > @retval EFI_NOT_READY Read the input key from the keybroad has not > finish. > > **/ > EFI_STATUS > PxeBcExtractBootFileUrl ( > + IN PXEBC_PRIVATE_DATA *Private, > OUT UINT8 **FileName, > IN OUT EFI_IPv6_ADDRESS *SrvAddr, > IN CHAR8 *BootFile, > IN UINT16 Length > ) > @@ -245,12 +410,16 @@ PxeBcExtractBootFileUrl ( > CHAR8 *TmpStr; > CHAR8 TmpChar; > CHAR8 *ServerAddressOption; > CHAR8 *ServerAddress; > CHAR8 *ModeStr; > + CHAR16 *HostName; > + BOOLEAN IpExpressedUrl; > + UINTN Len; > EFI_STATUS Status; > > + IpExpressedUrl = TRUE; > // > // 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 > @@ -262,12 +431,12 @@ PxeBcExtractBootFileUrl ( > // | | > // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ > // > > // > - // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile- > url format > - // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME > + // Based upon RFC 5970 and UEFI 2.6, bootfile-url format can be > + // tftp://[SERVER_ADDRESS]/BOOTFILE_NAME or > tftp://domain_name/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 = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX); > > @@ -289,47 +458,80 @@ PxeBcExtractBootFileUrl ( > > // > // Get the part of SERVER_ADDRESS string. > // > ServerAddressOption = TmpStr; > - if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) { > - FreePool (TmpStr); > - return EFI_INVALID_PARAMETER; > - } > + if (*ServerAddressOption == PXEBC_ADDR_START_DELIMITER) { > + ServerAddressOption ++; > + ServerAddress = ServerAddressOption; > + while (*ServerAddress != '\0' && *ServerAddress != > PXEBC_ADDR_END_DELIMITER) { > + ServerAddress++; > + } > + > + if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) { > + FreePool (TmpStr); > + return EFI_INVALID_PARAMETER; > + } > + > + *ServerAddress = '\0'; > + > + // > + // Convert the string of server address to Ipv6 address format and > store it. > + // > + Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); > + if (EFI_ERROR (Status)) { > + FreePool (TmpStr); > + return Status; > + } > > - ServerAddressOption ++; > - ServerAddress = ServerAddressOption; > - while (*ServerAddress != '\0' && *ServerAddress != > PXEBC_ADDR_END_DELIMITER) { > - ServerAddress++; > - } > + } else { > + IpExpressedUrl = FALSE; > + ServerAddress = ServerAddressOption; > + while (*ServerAddress != '\0' && *ServerAddress != > PXEBC_TFTP_URL_SEPARATOR) { > + ServerAddress++; > + } > > - if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) { > - FreePool (TmpStr); > - return EFI_INVALID_PARAMETER; > - } > + if (*ServerAddress != PXEBC_TFTP_URL_SEPARATOR) { > + FreePool (TmpStr); > + return EFI_INVALID_PARAMETER; > + } > + *ServerAddress = '\0'; > > - *ServerAddress = '\0'; > + Len = AsciiStrSize (ServerAddressOption); > + HostName = AllocateZeroPool (Len * sizeof (CHAR16)); > + if (HostName == NULL) { > + FreePool (TmpStr); > + return EFI_OUT_OF_RESOURCES; > + } > + AsciiStrToUnicodeStrS ( > + ServerAddressOption, > + HostName, > + Len > + ); > > - // > - // Convert the string of server address to Ipv6 address format and > store it. > - // > - Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr); > - if (EFI_ERROR (Status)) { > - FreePool (TmpStr); > - return Status; > + // > + // Perform DNS resolution. > + // > + Status = PxeBcDns6 (Private,HostName, SrvAddr); > + if (EFI_ERROR (Status)) { > + FreePool (TmpStr); > + return Status; > + } > } > > // > // Get the part of BOOTFILE_NAME string. > // > BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1); > - if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { > - FreePool (TmpStr); > - return EFI_INVALID_PARAMETER; > + if (IpExpressedUrl) { > + if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { > + FreePool (TmpStr); > + return EFI_INVALID_PARAMETER; > + } > + ++BootFileNamePtr; > } > > - ++BootFileNamePtr; > BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - > (UINTN)TmpStr) + 1); > if (BootFileNameLen != 0 || FileName != NULL) { > // > // Remove trailing mode=octet if present and ignore. All other modes > are > // invalid for netboot6, so reject them. > @@ -480,10 +682,12 @@ PxeBcParseDhcp6Packet ( > Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option; > } else if (NTOHS (Option->OpCode) == DHCP6_OPT_BOOT_FILE_PARAM) { > Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option; > } else if (NTOHS (Option->OpCode) == DHCP6_OPT_VENDOR_CLASS) { > Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option; > + } else if (NTOHS (Option->OpCode) == DHCP6_OPT_DNS_SERVERS) { > + Options[PXEBC_DHCP6_IDX_DNS_SERVER] = Option; > } > > Offset += (NTOHS (Option->OpLen) + 4); > Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset); > } > @@ -862,10 +1066,11 @@ PxeBcRetryDhcp6Binl ( > ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); > // > // Parse out the next server address from the last offer, and store > it > // > Status = PxeBcExtractBootFileUrl ( > + Private, > &Private->BootFileName, > &Private->ServerIp.v6, > (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]- > >Data), > NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]- > >OpLen) > ); > @@ -1113,10 +1318,18 @@ PxeBcHandleDhcp6Offer ( > SelectIndex = (UINT32) (Private->SelectIndex - 1); > ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM); > Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6; > Status = EFI_SUCCESS; > > + // > + // First try to cache DNS server address if DHCP6 offer provides. > + // > + if (Cache6->OptList[PXEBC_DHCP6_IDX_DNS_SERVER] != NULL) { > + Private->DnsServer = AllocateZeroPool (NTOHS (Cache6- > >OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->OpLen)); > + CopyMem (Private->DnsServer, Cache6- > >OptList[PXEBC_DHCP6_IDX_DNS_SERVER]->Data, sizeof (EFI_IPv6_ADDRESS)); > + } > + > if (Cache6->OfferType == PxeOfferTypeDhcpBinl) { > // > // DhcpBinl offer is selected, so need try to request bootfilename by > this offer. > // > if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) { > diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h > b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h > index a6d52f9..9493b16 100644 > --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h > +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h > @@ -31,11 +31,12 @@ > > #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_IDX_DNS_SERVER 4 > +#define PXEBC_DHCP6_IDX_MAX 5 > > #define PXEBC_DHCP6_BOOT_FILE_URL_PREFIX "tftp://" > #define PXEBC_TFTP_URL_SEPARATOR '/' > #define PXEBC_ADDR_START_DELIMITER '[' > #define PXEBC_ADDR_END_DELIMITER ']' > @@ -126,10 +127,11 @@ PxeBcFreeBootFileOption ( > > > /** > Parse the Boot File URL option. > > + @param[in] Private Pointer to PxeBc private data. > @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 > data. > @param[in] Length Length of the boot file URL option data. > > @@ -138,10 +140,11 @@ PxeBcFreeBootFileOption ( > @retval EFI_NOT_READY Read the input key from the keybroad has not > finish. > > **/ > EFI_STATUS > PxeBcExtractBootFileUrl ( > + IN PXEBC_PRIVATE_DATA *Private, > OUT UINT8 **FileName, > IN OUT EFI_IPv6_ADDRESS *SrvAddr, > IN CHAR8 *BootFile, > IN UINT16 Length > ); > diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h > b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h > index d0f5e5b..2cdc8bf 100644 > --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h > +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h > @@ -30,10 +30,11 @@ > #include <Protocol/Ip6Config.h> > #include <Protocol/Udp4.h> > #include <Protocol/Udp6.h> > #include <Protocol/Dhcp4.h> > #include <Protocol/Dhcp6.h> > +#include <Protocol/Dns6.h> > #include <Protocol/Mtftp4.h> > #include <Protocol/Mtftp6.h> > #include <Protocol/PxeBaseCode.h> > #include <Protocol/LoadFile.h> > #include <Protocol/PxeBaseCodeCallBack.h> > @@ -134,10 +135,11 @@ struct _PXEBC_PRIVATE_DATA { > EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; > EFI_DHCP6_PROTOCOL *Dhcp6; > EFI_MTFTP6_PROTOCOL *Mtftp6; > EFI_UDP6_PROTOCOL *Udp6Read; > EFI_UDP6_PROTOCOL *Udp6Write; > + EFI_DNS6_PROTOCOL *Dns6; > > 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; > @@ -167,10 +169,11 @@ struct _PXEBC_PRIVATE_DATA { > EFI_IP_ADDRESS TmpStationIp; > EFI_IP_ADDRESS StationIp; > EFI_IP_ADDRESS SubnetMask; > EFI_IP_ADDRESS GatewayIp; > EFI_IP_ADDRESS ServerIp; > + EFI_IPv6_ADDRESS *DnsServer; > UINT16 CurSrcPort; > UINT32 IaId; > > UINT32 Ip4MaxPacketSize; > UINT32 Ip6MaxPacketSize; > diff --git a/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf > b/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf > index c3ca218..6d1102b 100644 > --- a/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf > +++ b/NetworkPkg/UefiPxeBcDxe/UefiPxeBcDxe.inf > @@ -4,11 +4,11 @@ > # This driver provides PXE Base Code Protocol which is used to accessing > # PXE-compatible device for network access or booting. It could work > together > # with an IPv4 stack, an IPv6 stack or both. > # > # > -# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR> > +# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR> > # > # This program and the accompanying materials > # are licensed and made available under the terms and conditions of the > BSD License > # which accompanies this distribution. The full text of the license may > be found at > # http://opensource.org/licenses/bsd-license.php. > @@ -93,10 +93,12 @@ > gEfiUdp6ProtocolGuid ## TO_START > gEfiMtftp6ServiceBindingProtocolGuid ## TO_START > gEfiMtftp6ProtocolGuid ## TO_START > gEfiDhcp6ServiceBindingProtocolGuid ## TO_START > gEfiDhcp6ProtocolGuid ## TO_START > + gEfiDns6ServiceBindingProtocolGuid ## > SOMETIMES_CONSUMES > + gEfiDns6ProtocolGuid ## > SOMETIMES_CONSUMES > gEfiPxeBaseCodeCallbackProtocolGuid ## > SOMETIMES_PRODUCES > gEfiPxeBaseCodeProtocolGuid ## BY_START > gEfiLoadFileProtocolGuid ## BY_START > gEfiAdapterInformationProtocolGuid ## > SOMETIMES_CONSUMES > > -- > 1.9.5.msysgit.1 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel