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