diff options
Diffstat (limited to 'MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c')
-rw-r--r-- | MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c | 1866 |
1 files changed, 1866 insertions, 0 deletions
diff --git a/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c new file mode 100644 index 0000000000..8d7b3d03ef --- /dev/null +++ b/MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcImpl.c @@ -0,0 +1,1866 @@ +/** @file
+
+Copyright (c) 2007, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ PxeBcImpl.c
+
+Abstract:
+
+ Interface routines for PxeBc
+
+
+**/
+
+
+#include "PxeBcImpl.h"
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param UseIpv6 GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_ALREADY_STARTED GC_NOTO: Add description for
+ return value
+ @retval EFI_UNSUPPORTED GC_NOTO: Add description for
+ return value
+ @retval EFI_SUCCESS GC_NOTO: Add description for
+ return value
+
+**/
+EFI_STATUS
+EFIAPI
+EfiPxeBcStart (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN BOOLEAN UseIpv6
+ )
+{
+ PXEBC_PRIVATE_DATA *Private;
+ EFI_PXE_BASE_CODE_MODE *Mode;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+
+ if (Mode->Started) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (UseIpv6) {
+ //
+ // IPv6 is not supported now.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Configure the udp4 instance to let it receive data
+ //
+ Status = Private->Udp4->Configure (Private->Udp4, &Private->Udp4CfgData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->AddressIsOk = FALSE;
+
+ ZeroMem (Mode, sizeof (EFI_PXE_BASE_CODE_MODE));
+
+ Mode->Started = TRUE;
+ Mode->TTL = DEFAULT_TTL;
+ Mode->ToS = DEFAULT_ToS;
+ Mode->AutoArp = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_NOT_STARTED GC_NOTO: Add description for
+ return value
+ @retval EFI_SUCCESS GC_NOTO: Add description for
+ return value
+
+**/
+EFI_STATUS
+EFIAPI
+EfiPxeBcStop (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This
+ )
+{
+ PXEBC_PRIVATE_DATA *Private;
+ EFI_PXE_BASE_CODE_MODE *Mode;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+
+ if (!Mode->Started) {
+ return EFI_NOT_STARTED;
+ }
+
+ Mode->Started = FALSE;
+
+ Private->Udp4->Configure (Private->Udp4, NULL);
+
+ Private->Dhcp4->Stop (Private->Dhcp4);
+ Private->Dhcp4->Configure (Private->Dhcp4, NULL);
+
+ Private->FileSize = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param SortOffers GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_NOT_STARTED GC_NOTO: Add description for
+ return value
+
+**/
+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_DHCP4_PROTOCOL *Dhcp4;
+ EFI_DHCP4_CONFIG_DATA Dhcp4CfgData;
+ EFI_DHCP4_MODE_DATA Dhcp4Mode;
+ EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];
+ UINT32 OptCount;
+ UINT32 DiscoverTimeout;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+ Dhcp4 = Private->Dhcp4;
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP;
+ Private->SortOffers = SortOffers;
+
+ if (!Mode->Started) {
+ return EFI_NOT_STARTED;
+ }
+ //
+ // Initialize the DHCP options and build the option list
+ //
+ OptCount = PxeBcBuildDhcpOptions (Private, OptList, TRUE);
+
+ //
+ // Set the DHCP4 config data.
+ //
+ NetZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
+ Dhcp4CfgData.OptionCount = OptCount;
+ Dhcp4CfgData.OptionList = OptList;
+ Dhcp4CfgData.Dhcp4Callback = PxeBcDhcpCallBack;
+ Dhcp4CfgData.CallbackContext = Private;
+ Dhcp4CfgData.DiscoverTryCount = 1;
+ Dhcp4CfgData.DiscoverTimeout = &DiscoverTimeout;
+
+ for (Index = 0; Index < PXEBC_DHCP4_DISCOVER_RETRIES; Index++) {
+ //
+ // The four discovery timeouts are 4, 8, 16, 32 seconds respectively.
+ //
+ DiscoverTimeout = (PXEBC_DHCP4_DISCOVER_INIT_TIMEOUT << Index);
+
+ Status = Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Zero those arrays to record the varies numbers of DHCP OFFERS.
+ //
+ Private->NumOffers = 0;
+ Private->BootpIndex = 0;
+ NetZeroMem (Private->ServerCount, sizeof (Private->ServerCount));
+ NetZeroMem (Private->ProxyIndex, sizeof (Private->ProxyIndex));
+
+ Status = Dhcp4->Start (Dhcp4, NULL);
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_TIMEOUT) {
+ //
+ // If no response is received or all received offers don't match
+ // the PXE boot requirements, EFI_TIMEOUT will be returned.
+ //
+ continue;
+ }
+ //
+ // Other error status means the DHCP really fails.
+ //
+ break;
+ }
+
+ Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ ASSERT (Dhcp4Mode.State == Dhcp4Bound);
+
+ NetCopyMem (&Private->StationIp, &Dhcp4Mode.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
+ NetCopyMem (&Private->SubnetMask, &Dhcp4Mode.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
+ NetCopyMem (&Private->GatewayIp, &Dhcp4Mode.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
+
+ //
+ // Check the selected offer to see whether BINL is required, if no or BINL is
+ // finished, set the various Mode members.
+ //
+ Status = PxeBcCheckSelectedOffer (Private);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ Dhcp4->Stop (Dhcp4);
+ Dhcp4->Configure (Dhcp4, NULL);
+ } else {
+ //
+ // Remove the previously configured option list and callback function
+ //
+ NetZeroMem (&Dhcp4CfgData, sizeof (EFI_DHCP4_CONFIG_DATA));
+ Dhcp4->Configure (Dhcp4, &Dhcp4CfgData);
+
+ Private->AddressIsOk = TRUE;
+ }
+
+ return Status;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param Type GC_NOTO: add argument
+ description
+ @param Layer GC_NOTO: add argument
+ description
+ @param UseBis GC_NOTO: add argument
+ description
+ @param Info GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_NOT_STARTED GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+
+**/
+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;
+ EFI_PXE_BASE_CODE_SRVLIST DefaultSrvList;
+ PXEBC_CACHED_DHCP4_PACKET *Packet;
+ PXEBC_VENDOR_OPTION *VendorOpt;
+ UINT16 Index;
+ EFI_STATUS Status;
+ PXEBC_BOOT_SVR_ENTRY *BootSvrEntry;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+ BootSvrEntry = NULL;
+ SrvList = NULL;
+ Status = EFI_DEVICE_ERROR;
+ Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER;
+
+ if (!Private->AddressIsOk) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!Mode->Started) {
+ return EFI_NOT_STARTED;
+ }
+
+ //
+ // If layer isn't EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL,
+ // use the previous setting;
+ // If info isn't offered,
+ // use the cached DhcpAck and ProxyOffer packets.
+ //
+ if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) {
+
+ if (!Mode->PxeDiscoverValid || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DefaultInfo.IpCnt = 1;
+ DefaultInfo.UseUCast = TRUE;
+
+ DefaultSrvList.Type = Type;
+ DefaultSrvList.AcceptAnyResponse = FALSE;
+ DefaultSrvList.IpAddr.Addr[0] = Private->ServerIp.Addr[0];
+
+ SrvList = &DefaultSrvList;
+ Info = &DefaultInfo;
+ } else if (Info == NULL) {
+ //
+ // Create info by the cached packet before
+ //
+ Packet = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer : &Private->Dhcp4Ack;
+ VendorOpt = &Packet->PxeVendorOption;
+
+ if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {
+ //
+ // Address is not acquired or no discovery options.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DefaultInfo.UseMCast = (BOOLEAN)!IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);
+ DefaultInfo.UseBCast = (BOOLEAN)!IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);
+ DefaultInfo.MustUseList = (BOOLEAN) IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);
+ DefaultInfo.UseUCast = DefaultInfo.MustUseList;
+
+ if (DefaultInfo.UseMCast) {
+ //
+ // Get the multicast discover ip address from vendor option.
+ //
+ NetCopyMem (&DefaultInfo.ServerMCastIp.Addr, &VendorOpt->DiscoverMcastIp, sizeof (EFI_IPv4_ADDRESS));
+ }
+
+ DefaultInfo.IpCnt = 0;
+
+ if (DefaultInfo.MustUseList) {
+ BootSvrEntry = VendorOpt->BootSvr;
+ Status = EFI_INVALID_PARAMETER;
+
+ while (((UINT8) (BootSvrEntry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {
+
+ if (BootSvrEntry->Type == HTONS (Type)) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+
+ BootSvrEntry = GET_NEXT_BOOT_SVR_ENTRY (BootSvrEntry);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DefaultInfo.IpCnt = BootSvrEntry->IpCnt;
+ }
+
+ Info = &DefaultInfo;
+ } else {
+
+ SrvList = Info->SrvList;
+
+ if (!SrvList[0].AcceptAnyResponse) {
+
+ for (Index = 1; Index < Info->IpCnt; Index++) {
+ if (SrvList[Index].AcceptAnyResponse) {
+ break;
+ }
+ }
+
+ if (Index != Info->IpCnt) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if ((!Info->UseUCast && !Info->UseBCast && !Info->UseMCast) || (Info->MustUseList && Info->IpCnt == 0)) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Execute discover by UniCast/BroadCast/MultiCast
+ //
+ if (Info->UseUCast) {
+
+ for (Index = 0; Index < Info->IpCnt; Index++) {
+
+ if (BootSvrEntry == NULL) {
+ Private->ServerIp.Addr[0] = SrvList[Index].IpAddr.Addr[0];
+ } else {
+ NetCopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));
+ }
+
+ Status = PxeBcDiscvBootService (
+ Private,
+ Type,
+ Layer,
+ UseBis,
+ &SrvList[Index].IpAddr,
+ 0,
+ NULL,
+ TRUE,
+ &Private->PxeReply.Packet.Ack
+ );
+ }
+
+ } else if (Info->UseMCast) {
+
+ Status = PxeBcDiscvBootService (
+ Private,
+ Type,
+ Layer,
+ UseBis,
+ &Info->ServerMCastIp,
+ 0,
+ NULL,
+ TRUE,
+ &Private->PxeReply.Packet.Ack
+ );
+
+ } else if (Info->UseBCast) {
+
+ Status = PxeBcDiscvBootService (
+ Private,
+ Type,
+ Layer,
+ UseBis,
+ NULL,
+ Info->IpCnt,
+ SrvList,
+ TRUE,
+ &Private->PxeReply.Packet.Ack
+ );
+ }
+
+ if (EFI_ERROR (Status) || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {
+
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ PxeBcParseCachedDhcpPacket (&Private->PxeReply);
+ }
+
+ if (Mode->PxeBisReplyReceived) {
+ NetCopyMem (&Private->ServerIp, &Mode->PxeReply.Dhcpv4.BootpSiAddr, sizeof (EFI_IPv4_ADDRESS));
+ }
+
+ return Status;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param Operation GC_NOTO: add argument
+ description
+ @param BufferPtr GC_NOTO: add argument
+ description
+ @param Overwrite GC_NOTO: add argument
+ description
+ @param BufferSize GC_NOTO: add argument
+ description
+ @param BlockSize GC_NOTO: add argument
+ description
+ @param ServerIp GC_NOTO: add argument
+ description
+ @param Filename GC_NOTO: add argument
+ description
+ @param Info GC_NOTO: add argument
+ description
+ @param DontUseBuffer GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+
+**/
+EFI_STATUS
+EFIAPI
+EfiPxeBcMtftp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN EFI_PXE_BASE_CODE_TFTP_OPCODE Operation,
+ IN OUT VOID *BufferPtr,
+ IN BOOLEAN Overwrite,
+ IN OUT UINT64 *BufferSize,
+ IN UINTN *BlockSize OPTIONAL,
+ IN EFI_IP_ADDRESS *ServerIp,
+ IN UINT8 *Filename,
+ IN EFI_PXE_BASE_CODE_MTFTP_INFO *Info OPTIONAL,
+ IN BOOLEAN DontUseBuffer
+ )
+{
+ PXEBC_PRIVATE_DATA *Private;
+ EFI_MTFTP4_CONFIG_DATA Mtftp4Config;
+ EFI_STATUS Status;
+
+ if ((This == NULL) ||
+ (Filename == NULL) ||
+ (BufferSize == NULL) ||
+ ((ServerIp == NULL) || !Ip4IsUnicast (NTOHL (ServerIp->Addr[0]), 0)) ||
+ ((BufferPtr == NULL) && DontUseBuffer) ||
+ ((BlockSize != NULL) && (*BlockSize < 512))) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_DEVICE_ERROR;
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+
+ Mtftp4Config.UseDefaultSetting = FALSE;
+ Mtftp4Config.TimeoutValue = PXEBC_MTFTP_TIMEOUT;
+ Mtftp4Config.TryCount = PXEBC_MTFTP_RETRIES;
+
+ NetCopyMem (&Mtftp4Config.StationIp, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));
+ NetCopyMem (&Mtftp4Config.SubnetMask, &Private->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
+ NetCopyMem (&Mtftp4Config.GatewayIp, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));
+ NetCopyMem (&Mtftp4Config.ServerIp, ServerIp, sizeof (EFI_IPv4_ADDRESS));
+
+ switch (Operation) {
+
+ case EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE:
+
+ Status = PxeBcTftpGetFileSize (
+ Private,
+ &Mtftp4Config,
+ Filename,
+ BlockSize,
+ BufferSize
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ break;
+
+ case EFI_PXE_BASE_CODE_TFTP_READ_FILE:
+
+ Status = PxeBcTftpReadFile (
+ Private,
+ &Mtftp4Config,
+ Filename,
+ BlockSize,
+ BufferPtr,
+ BufferSize,
+ DontUseBuffer
+ );
+
+ break;
+
+ case EFI_PXE_BASE_CODE_TFTP_WRITE_FILE:
+
+ Status = PxeBcTftpWriteFile (
+ Private,
+ &Mtftp4Config,
+ Filename,
+ Overwrite,
+ BlockSize,
+ BufferPtr,
+ BufferSize
+ );
+
+ break;
+
+ case EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY:
+
+ Status = PxeBcTftpReadDirectory (
+ Private,
+ &Mtftp4Config,
+ 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 = EFI_UNSUPPORTED;
+ break;
+
+ default:
+
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ }
+
+ return Status;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param OpFlags GC_NOTO: add argument
+ description
+ @param DestIp GC_NOTO: add argument
+ description
+ @param DestPort GC_NOTO: add argument
+ description
+ @param GatewayIp GC_NOTO: add argument
+ description
+ @param SrcIp GC_NOTO: add argument
+ description
+ @param SrcPort GC_NOTO: add argument
+ description
+ @param HeaderSize GC_NOTO: add argument
+ description
+ @param HeaderPtr GC_NOTO: add argument
+ description
+ @param BufferSize GC_NOTO: add argument
+ description
+ @param BufferPtr GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for
+ return value
+
+**/
+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_UDP4_PROTOCOL *Udp4;
+ EFI_UDP4_COMPLETION_TOKEN Token;
+ EFI_UDP4_TRANSMIT_DATA *Udp4TxData;
+ UINT32 FragCount;
+ UINT32 DataLength;
+ EFI_UDP4_SESSION_DATA Udp4Session;
+ EFI_STATUS Status;
+ BOOLEAN IsDone;
+ UINT16 RandomSrcPort;
+
+ IsDone = FALSE;
+
+ if ((This == NULL) || (DestIp == NULL) || (DestPort == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((GatewayIp != NULL) && !Ip4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) {
+ //
+ // Gateway is provided but it's not a unicast IP address.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((HeaderSize != NULL) && ((*HeaderSize == 0) || (HeaderPtr == NULL))) {
+ //
+ // The HeaderSize ptr isn't NULL and: 1. the value is zero; or 2. the HeaderPtr
+ // is NULL.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BufferSize == NULL) || ((*BufferSize != 0) && (BufferPtr == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Udp4 = Private->Udp4;
+
+ if (!Private->AddressIsOk && (SrcIp == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SrcIp == NULL) {
+ SrcIp = &Private->StationIp;
+
+ if (GatewayIp == NULL) {
+ GatewayIp = &Private->GatewayIp;
+ }
+ }
+
+ if ((SrcPort == NULL) || (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT)) {
+ RandomSrcPort = (UINT16) (NET_RANDOM (NetRandomInitSeed ()) % 10000 + 1024);
+
+ if (SrcPort == NULL) {
+
+ SrcPort = &RandomSrcPort;
+ } else {
+
+ *SrcPort = RandomSrcPort;
+ }
+ }
+
+ ZeroMem (&Token, sizeof (EFI_UDP4_COMPLETION_TOKEN));
+ ZeroMem (&Udp4Session, sizeof (EFI_UDP4_SESSION_DATA));
+
+ NetCopyMem (&Udp4Session.DestinationAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));
+ Udp4Session.DestinationPort = *DestPort;
+ NetCopyMem (&Udp4Session.SourceAddress, SrcIp, sizeof (EFI_IPv4_ADDRESS));
+ Udp4Session.SourcePort = *SrcPort;
+
+ FragCount = (HeaderSize != NULL) ? 2 : 1;
+ Udp4TxData = (EFI_UDP4_TRANSMIT_DATA *) NetAllocatePool (sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA));
+ if (Udp4TxData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Udp4TxData->FragmentCount = FragCount;
+ Udp4TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32) *BufferSize;
+ Udp4TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
+ DataLength = (UINT32) *BufferSize;
+
+ if (FragCount == 2) {
+
+ Udp4TxData->FragmentTable[0].FragmentLength = (UINT32) *HeaderSize;
+ Udp4TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
+ DataLength += (UINT32) *HeaderSize;
+ }
+
+ Udp4TxData->GatewayAddress = (EFI_IPv4_ADDRESS *) GatewayIp;
+ Udp4TxData->UdpSessionData = &Udp4Session;
+ Udp4TxData->DataLength = DataLength;
+ Token.Packet.TxData = Udp4TxData;
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NET_TPL_EVENT,
+ PxeBcCommonNotify,
+ &IsDone,
+ &Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Status = Udp4->Transmit (Udp4, &Token);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ while (!IsDone) {
+
+ Udp4->Poll (Udp4);
+ }
+
+ Status = Token.Status;
+
+ON_EXIT:
+
+ if (Token.Event != NULL) {
+ gBS->CloseEvent (Token.Event);
+ }
+
+ NetFreePool (Udp4TxData);
+
+ return Status;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param OpFlags GC_NOTO: add argument
+ description
+ @param DestIp GC_NOTO: add argument
+ description
+ @param DestPort GC_NOTO: add argument
+ description
+ @param SrcIp GC_NOTO: add argument
+ description
+ @param SrcPort GC_NOTO: add argument
+ description
+ @param HeaderSize GC_NOTO: add argument
+ description
+ @param HeaderPtr GC_NOTO: add argument
+ description
+ @param BufferSize GC_NOTO: add argument
+ description
+ @param BufferPtr GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_NOT_STARTED GC_NOTO: Add description for
+ return value
+ @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for
+ return value
+
+**/
+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_PROTOCOL *Udp4;
+ EFI_UDP4_COMPLETION_TOKEN Token;
+ EFI_UDP4_RECEIVE_DATA *RxData;
+ EFI_UDP4_SESSION_DATA *Session;
+ EFI_STATUS Status;
+ BOOLEAN IsDone;
+ BOOLEAN Matched;
+ UINTN CopyLen;
+
+ if (This == NULL || DestIp == NULL || DestPort == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && (DestPort == NULL)) ||
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) && (SrcIp == NULL)) ||
+ (!(OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) && (SrcPort == NULL))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((HeaderSize != NULL) && (*HeaderSize == 0)) || ((HeaderPtr == NULL) && (*HeaderSize != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BufferSize == NULL) || ((BufferPtr == NULL) && (*BufferSize != 0))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+ Udp4 = Private->Udp4;
+
+ if (!Mode->Started) {
+ return EFI_NOT_STARTED;
+ }
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NET_TPL_EVENT,
+ PxeBcCommonNotify,
+ &IsDone,
+ &Token.Event
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IsDone = FALSE;
+ Status = Udp4->Receive (Udp4, &Token);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ Udp4->Poll (Udp4);
+
+ if (!IsDone) {
+ Status = EFI_TIMEOUT;
+ } else {
+
+ //
+ // check whether this packet matches the filters
+ //
+ if (EFI_ERROR (Token.Status)){
+ goto ON_EXIT;
+ }
+
+ RxData = Token.Packet.RxData;
+ Session = &RxData->UdpSession;
+
+ Matched = FALSE;
+
+ //
+ // Match the destination ip of the received udp dgram
+ //
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) {
+ Matched = TRUE;
+
+ if (DestIp != NULL) {
+ NetCopyMem (DestIp, &Session->DestinationAddress, sizeof (EFI_IPv4_ADDRESS));
+ }
+ } else {
+ if (DestIp != NULL) {
+ if (EFI_IP4_EQUAL (DestIp, &Session->DestinationAddress)) {
+ Matched = TRUE;
+ }
+ } else {
+ if (EFI_IP4_EQUAL (&Private->StationIp, &Session->DestinationAddress)) {
+ Matched = TRUE;
+ }
+ }
+ }
+
+ if (Matched) {
+ //
+ // Match the destination port of the received udp dgram
+ //
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) {
+
+ if (DestPort != NULL) {
+ *DestPort = Session->DestinationPort;
+ }
+ } else {
+
+ if (*DestPort != Session->DestinationPort) {
+ Matched = FALSE;
+ }
+ }
+ }
+
+ if (Matched) {
+ //
+ // Match the source ip of the received udp dgram
+ //
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) {
+
+ if (SrcIp != NULL) {
+ NetCopyMem (SrcIp, &Session->SourceAddress, sizeof (EFI_IPv4_ADDRESS));
+ }
+ } else {
+
+ if (!EFI_IP4_EQUAL (SrcIp, &Session->SourceAddress)) {
+ Matched = FALSE;
+ }
+ }
+ }
+
+ if (Matched) {
+ //
+ // Match the source port of the received udp dgram
+ //
+ if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {
+
+ if (SrcPort != NULL) {
+ *SrcPort = Session->SourcePort;
+ }
+ } else {
+
+ if (*SrcPort != Session->SourcePort) {
+ Matched = FALSE;
+ }
+ }
+ }
+
+ if (Matched) {
+
+ CopyLen = 0;
+
+ if (HeaderSize != NULL) {
+ CopyLen = MIN (*HeaderSize, RxData->DataLength);
+ NetCopyMem (HeaderPtr, RxData->FragmentTable[0].FragmentBuffer, CopyLen);
+ *HeaderSize = CopyLen;
+ }
+
+ if (RxData->DataLength - CopyLen > *BufferSize) {
+
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+
+ *BufferSize = RxData->DataLength - CopyLen;
+ NetCopyMem (BufferPtr, (UINT8 *) RxData->FragmentTable[0].FragmentBuffer + CopyLen, *BufferSize);
+ }
+ } else {
+
+ Status = EFI_TIMEOUT;
+ }
+
+ //
+ // Recycle the RxData
+ //
+ gBS->SignalEvent (RxData->RecycleSignal);
+ }
+
+ON_EXIT:
+
+ Udp4->Cancel (Udp4, &Token);
+
+ gBS->CloseEvent (Token.Event);
+
+ return Status;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param NewFilter GC_NOTO: add argument
+ description
+
+ @retval EFI_UNSUPPORTED GC_NOTO: Add description for
+ return value
+
+**/
+EFI_STATUS
+EFIAPI
+EfiPxeBcSetIpFilter (
+ IN EFI_PXE_BASE_CODE_PROTOCOL *This,
+ IN EFI_PXE_BASE_CODE_IP_FILTER *NewFilter
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param IpAddr GC_NOTO: add argument
+ description
+ @param MacAddr GC_NOTO: add argument
+ description
+
+ @retval EFI_UNSUPPORTED GC_NOTO: Add description for
+ return value
+
+**/
+EFI_STATUS
+EFIAPI
+EfiPxeBcArp (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_IP_ADDRESS * IpAddr,
+ IN EFI_MAC_ADDRESS * MacAddr OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param NewAutoArp GC_NOTO: add argument
+ description
+ @param NewSendGUID GC_NOTO: add argument
+ description
+ @param NewTTL GC_NOTO: add argument
+ description
+ @param NewToS GC_NOTO: add argument
+ description
+ @param NewMakeCallback GC_NOTO: add argument
+ description
+
+ @return GC_NOTO: add return values
+
+**/
+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_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ if (This == NULL) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+
+ if (NewSendGUID != NULL && *NewSendGUID == TRUE) {
+ //
+ // FixMe, cann't locate SendGuid
+ //
+ }
+
+ if (NewMakeCallback != NULL && *NewMakeCallback == TRUE) {
+
+ Status = gBS->HandleProtocol (
+ Private->Controller,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ (VOID **) &Private->PxeBcCallback
+ );
+ if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
+
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ }
+
+ if (!Mode->Started) {
+ Status = EFI_NOT_STARTED;
+ goto ON_EXIT;
+ }
+
+ if (NewMakeCallback != NULL) {
+
+ if (*NewMakeCallback) {
+ //
+ // Update the Callback protocol.
+ //
+ Status = gBS->HandleProtocol (
+ Private->Controller,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ (VOID **) &Private->PxeBcCallback
+ );
+
+ if (EFI_ERROR (Status) || (Private->PxeBcCallback->Callback == NULL)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ON_EXIT;
+ }
+ } else {
+ Private->PxeBcCallback = NULL;
+ }
+
+ Mode->MakeCallbacks = *NewMakeCallback;
+ }
+
+ if (NewAutoArp != NULL) {
+ Mode->AutoArp = *NewAutoArp;
+ }
+
+ if (NewSendGUID != NULL) {
+ Mode->SendGUID = *NewSendGUID;
+ }
+
+ if (NewTTL != NULL) {
+ Mode->TTL = *NewTTL;
+ }
+
+ if (NewToS != NULL) {
+ Mode->ToS = *NewToS;
+ }
+
+ON_EXIT:
+ return Status;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param NewStationIp GC_NOTO: add argument
+ description
+ @param NewSubnetMask GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_NOT_STARTED GC_NOTO: Add description for
+ return value
+ @retval EFI_SUCCESS GC_NOTO: Add description for
+ return value
+
+**/
+EFI_STATUS
+EFIAPI
+EfiPxeBcSetStationIP (
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This,
+ IN EFI_IP_ADDRESS * NewStationIp, OPTIONAL
+ IN EFI_IP_ADDRESS * NewSubnetMask OPTIONAL
+ )
+{
+ PXEBC_PRIVATE_DATA *Private;
+ EFI_PXE_BASE_CODE_MODE *Mode;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NewStationIp != NULL && !Ip4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NewSubnetMask != NULL && !IP4_IS_VALID_NETMASK (NTOHL (NewSubnetMask->Addr[0]))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+
+ if (!Mode->Started) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (NewStationIp != NULL) {
+ Mode->StationIp = *NewStationIp;
+ }
+
+ if (NewSubnetMask != NULL) {
+ Mode->SubnetMask = *NewSubnetMask;
+ }
+
+ Private->AddressIsOk = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param NewDhcpDiscoverValid GC_NOTO: add argument
+ description
+ @param NewDhcpAckReceived GC_NOTO: add argument
+ description
+ @param NewProxyOfferReceived GC_NOTO: add argument
+ description
+ @param NewPxeDiscoverValid GC_NOTO: add argument
+ description
+ @param NewPxeReplyReceived GC_NOTO: add argument
+ description
+ @param NewPxeBisReplyReceived GC_NOTO: add argument
+ description
+ @param NewDhcpDiscover GC_NOTO: add argument
+ description
+ @param NewDhcpAck GC_NOTO: add argument
+ description
+ @param NewProxyOffer GC_NOTO: add argument
+ description
+ @param NewPxeDiscover GC_NOTO: add argument
+ description
+ @param NewPxeReply GC_NOTO: add argument
+ description
+ @param NewPxeBisReply GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_NOT_STARTED GC_NOTO: Add description for
+ return value
+ @retval EFI_SUCCESS GC_NOTO: Add description for
+ return value
+
+**/
+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 == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);
+ Mode = Private->PxeBc.Mode;
+
+ if (!Mode->Started) {
+ return EFI_NOT_STARTED;
+ }
+
+ Private->FileSize = 0;
+
+ if (NewDhcpDiscoverValid != NULL) {
+ Mode->DhcpDiscoverValid = *NewDhcpDiscoverValid;
+ }
+
+ if (NewDhcpAckReceived != NULL) {
+ Mode->DhcpAckReceived = *NewDhcpAckReceived;
+ }
+
+ if (NewProxyOfferReceived != NULL) {
+ Mode->ProxyOfferReceived = *NewProxyOfferReceived;
+ }
+
+ if (NewPxeDiscoverValid != NULL) {
+ Mode->PxeDiscoverValid = *NewPxeDiscoverValid;
+ }
+
+ if (NewPxeReplyReceived != NULL) {
+ Mode->PxeReplyReceived = *NewPxeReplyReceived;
+ }
+
+ if (NewPxeBisReplyReceived != NULL) {
+ Mode->PxeBisReplyReceived = *NewPxeBisReplyReceived;
+ }
+
+ if (NewDhcpDiscover != NULL) {
+ NetCopyMem (&Mode->DhcpDiscover, NewDhcpDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
+ }
+
+ if (NewDhcpAck != NULL) {
+ NetCopyMem (&Mode->DhcpAck, NewDhcpAck, sizeof (EFI_PXE_BASE_CODE_PACKET));
+ }
+
+ if (NewProxyOffer != NULL) {
+ NetCopyMem (&Mode->ProxyOffer, NewProxyOffer, sizeof (EFI_PXE_BASE_CODE_PACKET));
+ }
+
+ if (NewPxeDiscover != NULL) {
+ NetCopyMem (&Mode->PxeDiscover, NewPxeDiscover, sizeof (EFI_PXE_BASE_CODE_PACKET));
+ }
+
+ if (NewPxeReply != NULL) {
+ NetCopyMem (&Mode->PxeReply, NewPxeReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
+ }
+
+ if (NewPxeBisReply != NULL) {
+ NetCopyMem (&Mode->PxeBisReply, NewPxeBisReply, sizeof (EFI_PXE_BASE_CODE_PACKET));
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_PXE_BASE_CODE_PROTOCOL mPxeBcProtocolTemplate = {
+ EFI_PXE_BASE_CODE_PROTOCOL_REVISION,
+ EfiPxeBcStart,
+ EfiPxeBcStop,
+ EfiPxeBcDhcp,
+ EfiPxeBcDiscover,
+ EfiPxeBcMtftp,
+ EfiPxeBcUdpWrite,
+ EfiPxeBcUdpRead,
+ EfiPxeBcSetIpFilter,
+ EfiPxeBcArp,
+ EfiPxeBcSetParameters,
+ EfiPxeBcSetStationIP,
+ EfiPxeBcSetPackets,
+ NULL
+};
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param Function GC_NOTO: add argument
+ description
+ @param Received GC_NOTO: add argument
+ description
+ @param PacketLength GC_NOTO: add argument
+ description
+ @param PacketPtr GC_NOTO: add argument
+ description
+
+ @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT GC_NOTO: Add description for
+ return value
+ @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
+ return value
+ @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
+ return value
+ @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
+ return value
+ @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE GC_NOTO: Add description for
+ return value
+
+**/
+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 = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+
+ if (!EFI_ERROR (Status)) {
+
+ if (Key.ScanCode == SCAN_ESC || Key.UnicodeChar == (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 != 0 && PacketPtr != NULL) {
+ if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
+ }
+ }
+ break;
+
+ case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
+ case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
+ break;
+
+ default:
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
+ }
+
+ if (PacketLength != 0 && PacketPtr != NULL) {
+ //
+ // Print '.' when transmit a packet
+ //
+ AsciiPrint (".");
+
+ }
+
+ return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
+}
+
+EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL mPxeBcCallBackTemplate = {
+ EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
+ EfiPxeLoadFileCallback
+};
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param Private GC_NOTO: add argument
+ description
+ @param BufferSize GC_NOTO: add argument
+ description
+ @param Buffer GC_NOTO: add argument
+ description
+
+ @return GC_NOTO: add return values
+
+**/
+EFI_STATUS
+DiscoverBootFile (
+ IN PXEBC_PRIVATE_DATA *Private,
+ IN OUT UINT64 *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
+ EFI_PXE_BASE_CODE_MODE *Mode;
+ EFI_STATUS Status;
+ UINT16 Type;
+ UINT16 Layer;
+ BOOLEAN UseBis;
+ UINTN BlockSize;
+ PXEBC_CACHED_DHCP4_PACKET *Packet;
+ UINT16 Value;
+
+ PxeBc = &Private->PxeBc;
+ Mode = PxeBc->Mode;
+ Type = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;
+ Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;
+
+ //
+ // do DHCP.
+ //
+ Status = PxeBc->Dhcp (PxeBc, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select a boot server
+ //
+ Status = PxeBcSelectBootPrompt (Private);
+
+ if (Status == EFI_SUCCESS) {
+ Status = PxeBcSelectBootMenu (Private, &Type, TRUE);
+ } else if (Status == EFI_TIMEOUT) {
+ Status = PxeBcSelectBootMenu (Private, &Type, FALSE);
+ }
+
+ if (!EFI_ERROR (Status)) {
+
+ if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {
+ //
+ // Local boot(PXE bootstrap server) need abort
+ //
+ return EFI_ABORTED;
+ }
+
+ UseBis = (BOOLEAN) (Mode->BisSupported && Mode->BisDetected);
+ Status = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ *BufferSize = 0;
+ BlockSize = 0x8000;
+
+ //
+ // Get bootfile name and (m)tftp server ip addresss
+ //
+ if (Mode->PxeReplyReceived) {
+ Packet = &Private->PxeReply;
+ } else if (Mode->ProxyOfferReceived) {
+ Packet = &Private->ProxyOffer;
+ } else {
+ Packet = &Private->Dhcp4Ack;
+ }
+
+ NetCopyMem (&Private->ServerIp, &Packet->Packet.Offer.Dhcp4.Header.ServerAddr, sizeof (EFI_IPv4_ADDRESS));
+ if (Private->ServerIp.Addr[0] == 0) {
+ //
+ // next server ip address is zero, use option 54 instead
+ //
+ NetCopyMem (
+ &Private->ServerIp,
+ Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
+ sizeof (EFI_IPv4_ADDRESS)
+ );
+ }
+
+ ASSERT (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);
+
+ //
+ // bootlfile name
+ //
+ Private->BootFileName = (CHAR8 *) (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data);
+
+ if (Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
+ //
+ // Already have the bootfile length option, compute the file size
+ //
+ NetCopyMem (&Value, Packet->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
+ Value = NTOHS (Value);
+ *BufferSize = 512 * Value;
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Get the bootfile size from tftp
+ //
+ Status = PxeBc->Mtftp (
+ PxeBc,
+ EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
+ Buffer,
+ FALSE,
+ BufferSize,
+ &BlockSize,
+ &Private->ServerIp,
+ (UINT8 *) Private->BootFileName,
+ NULL,
+ FALSE
+ );
+ }
+
+ Private->FileSize = (UINTN) *BufferSize;
+
+ return Status;
+}
+
+
+/**
+ GC_NOTO: Add function description
+
+ @param This GC_NOTO: add argument
+ description
+ @param FilePath GC_NOTO: add argument
+ description
+ @param BootPolicy GC_NOTO: add argument
+ description
+ @param BufferSize GC_NOTO: add argument
+ description
+ @param Buffer GC_NOTO: add argument
+ description
+
+ @retval EFI_INVALID_PARAMETER GC_NOTO: Add description for
+ return value
+ @retval EFI_UNSUPPORTED GC_NOTO: Add description for
+ return value
+
+**/
+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;
+ EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
+ BOOLEAN NewMakeCallback;
+ UINTN BlockSize;
+ EFI_STATUS Status;
+ UINT64 TmpBufSize;
+
+ Private = PXEBC_PRIVATE_DATA_FROM_LOADFILE (This);
+ PxeBc = &Private->PxeBc;
+ NewMakeCallback = FALSE;
+ BlockSize = 0x8000;
+ Status = EFI_DEVICE_ERROR;
+
+ if (This == NULL || BufferSize == NULL) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only support BootPolicy
+ //
+ if (!BootPolicy) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = PxeBc->Start (PxeBc, FALSE);
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (
+ Private->Controller,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ (VOID **) &Private->PxeBcCallback
+ );
+ if (Status == EFI_UNSUPPORTED) {
+
+ CopyMem (&Private->LoadFileCallback, &mPxeBcCallBackTemplate, sizeof (Private->LoadFileCallback));
+
+ Status = gBS->InstallProtocolInterface (
+ &Private->Controller,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Private->LoadFileCallback
+ );
+
+ NewMakeCallback = (BOOLEAN) (Status == EFI_SUCCESS);
+
+ Status = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
+ if (EFI_ERROR (Status)) {
+ PxeBc->Stop (PxeBc);
+ return Status;
+ }
+ }
+
+ if (Private->FileSize == 0) {
+ TmpBufSize = 0;
+ Status = DiscoverBootFile (Private, &TmpBufSize, Buffer);
+
+ if (sizeof (UINTN) < sizeof (UINT64) && (TmpBufSize > 0xFFFFFFFF)) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ *BufferSize = (UINTN) TmpBufSize;
+ }
+ } else if (Buffer == NULL) {
+ *BufferSize = Private->FileSize;
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ //
+ // Download the file.
+ //
+ TmpBufSize = (UINT64) (*BufferSize);
+ Status = PxeBc->Mtftp (
+ PxeBc,
+ EFI_PXE_BASE_CODE_TFTP_READ_FILE,
+ Buffer,
+ FALSE,
+ &TmpBufSize,
+ &BlockSize,
+ &Private->ServerIp,
+ (UINT8 *) Private->BootFileName,
+ NULL,
+ FALSE
+ );
+ }
+ //
+ // If we added a callback protocol, now is the time to remove it.
+ //
+ if (NewMakeCallback) {
+
+ NewMakeCallback = FALSE;
+
+ PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
+
+ gBS->UninstallProtocolInterface (
+ Private->Controller,
+ &gEfiPxeBaseCodeCallbackProtocolGuid,
+ &Private->LoadFileCallback
+ );
+ }
+ //
+ // Check download status
+ //
+ switch (Status) {
+
+ case EFI_SUCCESS:
+ break;
+
+ case EFI_BUFFER_TOO_SMALL:
+ if (Buffer != NULL) {
+ AsciiPrint ("PXE-E05: Download buffer is smaller than requested file.\n");
+ } else {
+ return Status;
+ }
+ break;
+
+ case EFI_DEVICE_ERROR:
+ AsciiPrint ("PXE-E07: Network device error.\n");
+ break;
+
+ case EFI_OUT_OF_RESOURCES:
+ AsciiPrint ("PXE-E09: Could not allocate I/O buffers.\n");
+ break;
+
+ case EFI_NO_MEDIA:
+ AsciiPrint ("PXE-E12: Could not detect network connection.\n");
+ break;
+
+ case EFI_NO_RESPONSE:
+ AsciiPrint ("PXE-E16: No offer received.\n");
+ break;
+
+ case EFI_TIMEOUT:
+ AsciiPrint ("PXE-E18: Server response timeout.\n");
+ break;
+
+ case EFI_ABORTED:
+ AsciiPrint ("PXE-E21: Remote boot cancelled.\n");
+ break;
+
+ case EFI_ICMP_ERROR:
+ AsciiPrint ("PXE-E22: Client received ICMP error from server.\n");
+ break;
+
+ case EFI_TFTP_ERROR:
+ AsciiPrint ("PXE-E23: Client received TFTP error from server.\n");
+ break;
+
+ default:
+ AsciiPrint ("PXE-E99: Unexpected network error.\n");
+ break;
+ }
+
+ PxeBc->Stop (PxeBc);
+
+ return Status;
+}
+
+EFI_LOAD_FILE_PROTOCOL mLoadFileProtocolTemplate = { EfiPxeLoadFile };
+
|