+\r
+ //\r
+ // Check that the controller (identified by its handle "Handle") supports the\r
+ // MTFTPv4 Service Binding Protocol. If it does, it means that it supports the\r
+ // EFI MTFTPv4 Protocol needed to download the image through TFTP.\r
+ //\r
+ Status = gBS->HandleProtocol (\r
+ Handle, &gEfiMtftp4ServiceBindingProtocolGuid,\r
+ &Interface\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Worker function that get the size in numbers of bytes of a file from a TFTP\r
+ server before to download the file.\r
+\r
+ @param[in] Mtftp4 MTFTP4 protocol interface\r
+ @param[in] FilePath Path of the file, Ascii encoded\r
+ @param[out] FileSize Address where to store the file size in number of\r
+ bytes.\r
+\r
+ @retval EFI_SUCCESS The size of the file was returned.\r
+ @retval !EFI_SUCCESS The size of the file was not returned.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4GetFileSize (\r
+ IN EFI_MTFTP4_PROTOCOL *Mtftp4,\r
+ IN CHAR8 *FilePath,\r
+ OUT UINT64 *FileSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_MTFTP4_OPTION ReqOpt[1];\r
+ EFI_MTFTP4_PACKET *Packet;\r
+ UINT32 PktLen;\r
+ EFI_MTFTP4_OPTION *TableOfOptions;\r
+ EFI_MTFTP4_OPTION *Option;\r
+ UINT32 OptCnt;\r
+ UINT8 OptBuf[128];\r
+\r
+ ReqOpt[0].OptionStr = (UINT8*)"tsize";\r
+ OptBuf[0] = '0';\r
+ OptBuf[1] = 0;\r
+ ReqOpt[0].ValueStr = OptBuf;\r
+\r
+ Status = Mtftp4->GetInfo (\r
+ Mtftp4,\r
+ NULL,\r
+ (UINT8*)FilePath,\r
+ NULL,\r
+ 1,\r
+ ReqOpt,\r
+ &PktLen,\r
+ &Packet\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ Status = Mtftp4->ParseOptions (\r
+ Mtftp4,\r
+ PktLen,\r
+ Packet,\r
+ (UINT32 *) &OptCnt,\r
+ &TableOfOptions\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Error;\r
+ }\r
+\r
+ Option = TableOfOptions;\r
+ while (OptCnt != 0) {\r
+ if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {\r
+ *FileSize = AsciiStrDecimalToUint64 ((CHAR8 *)Option->ValueStr);\r
+ break;\r
+ }\r
+ OptCnt--;\r
+ Option++;\r
+ }\r
+ FreePool (TableOfOptions);\r
+\r
+ if (OptCnt == 0) {\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+\r
+Error :\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Update the progress of a file download\r
+ This procedure is called each time a new TFTP packet is received.\r
+\r
+ @param[in] This MTFTP4 protocol interface\r
+ @param[in] Token Parameters for the download of the file\r
+ @param[in] PacketLen Length of the packet\r
+ @param[in] Packet Address of the packet\r
+\r
+ @retval EFI_SUCCESS All packets are accepted.\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+Mtftp4CheckPacket (\r
+ IN EFI_MTFTP4_PROTOCOL *This,\r
+ IN EFI_MTFTP4_TOKEN *Token,\r
+ IN UINT16 PacketLen,\r
+ IN EFI_MTFTP4_PACKET *Packet\r
+ )\r
+{\r
+ BDS_TFTP_CONTEXT *Context;\r
+ CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE];\r
+ UINT64 NbOfKb;\r
+ UINTN Index;\r
+ UINTN LastStep;\r
+ UINTN Step;\r
+ UINT64 LastNbOf50Kb;\r
+ UINT64 NbOf50Kb;\r
+\r
+ if ((NTOHS (Packet->OpCode)) == EFI_MTFTP4_OPCODE_DATA) {\r
+ Context = (BDS_TFTP_CONTEXT*)Token->Context;\r
+\r
+ if (Context->DownloadedNbOfBytes == 0) {\r
+ if (Context->FileSize > 0) {\r
+ Print (L"%s 0 Kb", mTftpProgressFrame);\r
+ } else {\r
+ Print (L" 0 Kb");\r
+ }\r
+ }\r
+\r
+ //\r
+ // The data is the packet are prepended with two UINT16 :\r
+ // . OpCode = EFI_MTFTP4_OPCODE_DATA\r
+ // . Block = the number of this block of data\r
+ //\r
+ Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode) - sizeof (Packet->Data.Block);\r
+ NbOfKb = Context->DownloadedNbOfBytes / 1024;\r
+\r
+ Progress[0] = L'\0';\r
+ if (Context->FileSize > 0) {\r
+ LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;\r
+ Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;\r
+ if (Step > LastStep) {\r
+ Print (mTftpProgressDelete);\r
+ CopyMem (Progress, mTftpProgressFrame, sizeof mTftpProgressFrame);\r
+ for (Index = 1; Index < Step; Index++) {\r
+ Progress[Index] = L'=';\r
+ }\r
+ Progress[Step] = L'>';\r
+\r
+ UnicodeSPrint (\r
+ Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,\r
+ sizeof (Progress) - sizeof (mTftpProgressFrame),\r
+ L" %7d Kb",\r
+ NbOfKb\r
+ );\r
+ Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;\r
+ }\r
+ } else {\r
+ //\r
+ // Case when we do not know the size of the final file.\r
+ // We print the updated size every 50KB of downloaded data\r
+ //\r
+ LastNbOf50Kb = Context->LastReportedNbOfBytes / (50*1024);\r
+ NbOf50Kb = Context->DownloadedNbOfBytes / (50*1024);\r
+ if (NbOf50Kb > LastNbOf50Kb) {\r
+ Print (L"\b\b\b\b\b\b\b\b\b\b");\r
+ UnicodeSPrint (Progress, sizeof (Progress), L"%7d Kb", NbOfKb);\r
+ Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;\r
+ }\r
+ }\r
+ if (Progress[0] != L'\0') {\r
+ Print (L"%s", Progress);\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r