EFI_STATUS BdsTftpLoadImage ( IN EFI_DEVICE_PATH* DevicePath, IN EFI_HANDLE Handle, IN EFI_DEVICE_PATH* RemainingDevicePath, IN EFI_ALLOCATE_TYPE Type, IN OUT EFI_PHYSICAL_ADDRESS *Image, OUT UINTN *ImageSize ) { EFI_STATUS Status; EFI_PXE_BASE_CODE_PROTOCOL *Pxe; UINT64 TftpBufferSize; VOID* TftpBuffer; EFI_IP_ADDRESS ServerIp; IPv4_DEVICE_PATH* IPv4DevicePathNode; FILEPATH_DEVICE_PATH* FilePathDevicePath; EFI_IP_ADDRESS LocalIp; ASSERT(IS_DEVICE_PATH_NODE(RemainingDevicePath,MESSAGING_DEVICE_PATH,MSG_IPv4_DP)); IPv4DevicePathNode = (IPv4_DEVICE_PATH*)RemainingDevicePath; FilePathDevicePath = (FILEPATH_DEVICE_PATH*)(IPv4DevicePathNode + 1); Status = gBS->LocateProtocol (&gEfiPxeBaseCodeProtocolGuid, NULL, (VOID **)&Pxe); if (EFI_ERROR(Status)) { return Status; } Status = Pxe->Start (Pxe, FALSE); if (EFI_ERROR(Status) && (Status != EFI_ALREADY_STARTED)) { return Status; } if (!IPv4DevicePathNode->StaticIpAddress) { Status = Pxe->Dhcp(Pxe, TRUE); } else { CopyMem (&LocalIp.v4, &IPv4DevicePathNode->LocalIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = Pxe->SetStationIp (Pxe, &LocalIp, NULL); } if (EFI_ERROR(Status)) { return Status; } CopyMem (&ServerIp.v4, &IPv4DevicePathNode->RemoteIpAddress, sizeof (EFI_IPv4_ADDRESS)); Status = Pxe->Mtftp ( Pxe, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, NULL, FALSE, &TftpBufferSize, NULL, &ServerIp, (UINT8 *)FilePathDevicePath->PathName, NULL, TRUE ); if (EFI_ERROR(Status)) { return Status; } // Allocate a buffer to hold the whole file. TftpBuffer = AllocatePool(TftpBufferSize); if (TftpBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } Status = Pxe->Mtftp ( Pxe, EFI_PXE_BASE_CODE_TFTP_READ_FILE, TftpBuffer, FALSE, &TftpBufferSize, NULL, &ServerIp, (UINT8 *)FilePathDevicePath->PathName, NULL, FALSE ); if (EFI_ERROR(Status)) { FreePool(TftpBuffer); } else if (ImageSize != NULL) { *ImageSize = (UINTN)TftpBufferSize; } return Status; }
/** Parse out the boot information from the last Dhcp4 reply packet. @param[in, out] Private Pointer to PxeBc private data. @param[out] BufferSize Size of the boot file to be downloaded. @retval EFI_SUCCESS Successfully parsed out all the boot information. @retval Others Failed to parse out the boot information. **/ EFI_STATUS PxeBcDhcp4BootInfo ( IN OUT PXEBC_PRIVATE_DATA *Private, OUT UINT64 *BufferSize ) { EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; EFI_PXE_BASE_CODE_MODE *Mode; EFI_STATUS Status; PXEBC_DHCP4_PACKET_CACHE *Cache4; UINT16 Value; PXEBC_VENDOR_OPTION *VendorOpt; PXEBC_BOOT_SVR_ENTRY *Entry; PxeBc = &Private->PxeBc; Mode = PxeBc->Mode; Status = EFI_SUCCESS; *BufferSize = 0; // // Get the last received Dhcp4 reply packet. // if (Mode->PxeReplyReceived) { Cache4 = &Private->PxeReply.Dhcp4; } else if (Mode->ProxyOfferReceived) { Cache4 = &Private->ProxyOffer.Dhcp4; } else { Cache4 = &Private->DhcpAck.Dhcp4; } ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL); // // Parse the boot server address. // If prompt/discover is disabled, get the first boot server from the boot servers list. // Otherwise, parse the boot server Ipv4 address from next server address field in DHCP header. // If all these fields are not available, use option 54 instead. // VendorOpt = &Cache4->VendorOpt; if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && IS_VALID_BOOT_SERVERS (VendorOpt->BitMap)) { Entry = VendorOpt->BootSvr; if (VendorOpt->BootSvrLen >= sizeof (PXEBC_BOOT_SVR_ENTRY) && Entry->IpCnt > 0) { CopyMem ( &Private->ServerIp, &Entry->IpAddr[0], sizeof (EFI_IPv4_ADDRESS) ); } } if (Private->ServerIp.Addr[0] == 0) { // // ServerIp.Addr[0] equals zero means we failed to get IP address from boot server list. // Try to use next server address field. // CopyMem ( &Private->ServerIp, &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr, sizeof (EFI_IPv4_ADDRESS) ); } if (Private->ServerIp.Addr[0] == 0) { // // Still failed , use the IP address from option 54. // CopyMem ( &Private->ServerIp, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data, sizeof (EFI_IPv4_ADDRESS) ); } // // Parse the boot file name by option. // Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data; if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) { // // Parse the boot file size by option. // CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value)); Value = NTOHS (Value); // // The field of boot file size is 512 bytes in unit. // *BufferSize = 512 * Value; } else { // // Get the bootfile size by tftp command if no option available. // Status = PxeBc->Mtftp ( PxeBc, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, NULL, FALSE, BufferSize, &Private->BlockSize, &Private->ServerIp, Private->BootFileName, NULL, FALSE ); } // // Save the value of boot file size. // Private->BootFileSize = (UINTN) *BufferSize; // // Display all the information: boot server address, boot file name and boot file size. // AsciiPrint ("\n Server IP address is "); PxeBcShowIp4Addr (&Private->ServerIp.v4); AsciiPrint ("\n NBP filename is %a", Private->BootFileName); AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize); return Status; }
/** Parse out the boot information from the last Dhcp6 reply packet. @param[in, out] Private Pointer to PxeBc private data. @param[out] BufferSize Size of the boot file to be downloaded. @retval EFI_SUCCESS Successfully parsed out all the boot information. @retval EFI_BUFFER_TOO_SMALL @retval Others Failed to parse out the boot information. **/ EFI_STATUS PxeBcDhcp6BootInfo ( IN OUT PXEBC_PRIVATE_DATA *Private, OUT UINT64 *BufferSize ) { EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; EFI_PXE_BASE_CODE_MODE *Mode; EFI_STATUS Status; PXEBC_DHCP6_PACKET_CACHE *Cache6; UINT16 Value; PxeBc = &Private->PxeBc; Mode = PxeBc->Mode; Status = EFI_SUCCESS; *BufferSize = 0; // // Get the last received Dhcp6 reply packet. // if (Mode->PxeReplyReceived) { Cache6 = &Private->PxeReply.Dhcp6; } else if (Mode->ProxyOfferReceived) { Cache6 = &Private->ProxyOffer.Dhcp6; } else { Cache6 = &Private->DhcpAck.Dhcp6; } 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; } // // 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. // Status = PxeBcExtractBootFileParam ((CHAR8 *) Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM]->Data, &Value); if (EFI_ERROR (Status)) { return Status; } // // The field of boot file size is 512 bytes in unit. // *BufferSize = 512 * Value; } else { // // Send get file size command by tftp if option unavailable. // Status = PxeBc->Mtftp ( PxeBc, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, NULL, FALSE, BufferSize, &Private->BlockSize, &Private->ServerIp, Private->BootFileName, NULL, FALSE ); } // // Save the value of boot file size. // Private->BootFileSize = (UINTN) *BufferSize; // // Display all the information: boot server address, boot file name and boot file size. // AsciiPrint ("\n Server IP address is "); PxeBcShowIp6Addr (&Private->ServerIp.v6); AsciiPrint ("\n NBP filename is %a", Private->BootFileName); AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize); return Status; }
/** Parse out the boot information from the last Dhcp4 reply packet. @param[in, out] Private Pointer to PxeBc private data. @param[out] BufferSize Size of the boot file to be downloaded. @retval EFI_SUCCESS Successfully parsed out all the boot information. @retval Others Failed to parse out the boot information. **/ EFI_STATUS PxeBcDhcp4BootInfo ( IN OUT PXEBC_PRIVATE_DATA *Private, OUT UINT64 *BufferSize ) { EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; EFI_PXE_BASE_CODE_MODE *Mode; EFI_STATUS Status; PXEBC_DHCP4_PACKET_CACHE *Cache4; UINT16 Value; PxeBc = &Private->PxeBc; Mode = PxeBc->Mode; Status = EFI_SUCCESS; *BufferSize = 0; // // Get the last received Dhcp4 reply packet. // if (Mode->PxeReplyReceived) { Cache4 = &Private->PxeReply.Dhcp4; } else if (Mode->ProxyOfferReceived) { Cache4 = &Private->ProxyOffer.Dhcp4; } else { Cache4 = &Private->DhcpAck.Dhcp4; } // // Parse the boot server Ipv4 address by next server address. // If this field isn't available, use option 54 instead. // CopyMem ( &Private->ServerIp, &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr, sizeof (EFI_IPv4_ADDRESS) ); if (Private->ServerIp.Addr[0] == 0) { CopyMem ( &Private->ServerIp, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data, sizeof (EFI_IPv4_ADDRESS) ); } // // Parse the boot file name by option. // ASSERT (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL); Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data; if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) { // // Parse the boot file size by option. // CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value)); Value = NTOHS (Value); // // The field of boot file size is 512 bytes in unit. // *BufferSize = 512 * Value; } else { // // Get the bootfile size by tftp command if no option available. // Status = PxeBc->Mtftp ( PxeBc, EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE, NULL, FALSE, BufferSize, &Private->BlockSize, &Private->ServerIp, Private->BootFileName, NULL, FALSE ); } // // Save the value of boot file size. // Private->BootFileSize = (UINTN) *BufferSize; // // Display all the information: boot server address, boot file name and boot file size. // AsciiPrint ("\n Server IP address is "); PxeBcShowIp4Addr (&Private->ServerIp.v4); AsciiPrint ("\n NBP filename is %a", Private->BootFileName); AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize); return Status; }