]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c
IntelFsp2WrapperPkg/FspmWrapperPeim: Update debug message match code.
[mirror_edk2.git] / ShellPkg / Library / UefiShellTftpCommandLib / Tftp.c
CommitLineData
68074260
RC
1/** @file\r
2 The implementation for the 'tftp' Shell command.\r
3\r
4 Copyright (c) 2015, ARM Ltd. All rights reserved.<BR>\r
6add86ab
JC
5 Copyright (c) 2015, Intel Corporation. All rights reserved. <BR>\r
6 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>\r
68074260
RC
7\r
8 This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php.\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15**/\r
16\r
17#include "UefiShellTftpCommandLib.h"\r
18\r
6add86ab
JC
19#define IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH 32\r
20\r
68074260
RC
21/*\r
22 Constant strings and definitions related to the message indicating the amount of\r
23 progress in the dowloading of a TFTP file.\r
24*/\r
25\r
26// Frame for the progression slider\r
27STATIC CONST CHAR16 mTftpProgressFrame[] = L"[ ]";\r
28\r
29// Number of steps in the progression slider\r
30#define TFTP_PROGRESS_SLIDER_STEPS ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 3)\r
31\r
32// Size in number of characters plus one (final zero) of the message to\r
33// indicate the progress of a TFTP download. The format is "[(progress slider:\r
34// 40 characters)] (nb of KBytes downloaded so far: 7 characters) Kb". There\r
35// are thus the number of characters in mTftpProgressFrame[] plus 11 characters\r
36// (2 // spaces, "Kb" and seven characters for the number of KBytes).\r
37#define TFTP_PROGRESS_MESSAGE_SIZE ((sizeof (mTftpProgressFrame) / sizeof (CHAR16)) + 12)\r
38\r
39// String to delete the TFTP progress message to be able to update it :\r
40// (TFTP_PROGRESS_MESSAGE_SIZE-1) '\b'\r
41STATIC CONST CHAR16 mTftpProgressDelete[] = L"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b";\r
42\r
0fcf66a4
QS
43/**\r
44 Check and convert the UINT16 option values of the 'tftp' command\r
45\r
46 @param[in] ValueStr Value as an Unicode encoded string\r
47 @param[out] Value UINT16 value\r
48\r
49 @return TRUE The value was returned.\r
50 @return FALSE A parsing error occured.\r
51**/\r
52STATIC \r
53BOOLEAN \r
54StringToUint16 (\r
68074260
RC
55 IN CONST CHAR16 *ValueStr,\r
56 OUT UINT16 *Value\r
57 );\r
58\r
0fcf66a4
QS
59/**\r
60 Get the name of the NIC.\r
61\r
62 @param[in] ControllerHandle The network physical device handle.\r
63 @param[in] NicNumber The network physical device number.\r
64 @param[out] NicName Address where to store the NIC name.\r
65 The memory area has to be at least\r
6add86ab
JC
66 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH \r
67 double byte wide.\r
0fcf66a4
QS
68\r
69 @return EFI_SUCCESS The name of the NIC was returned.\r
70 @return Others The creation of the child for the Managed\r
71 Network Service failed or the opening of\r
72 the Managed Network Protocol failed or\r
73 the operational parameters for the\r
74 Managed Network Protocol could not be\r
75 read.\r
76**/\r
77STATIC \r
78EFI_STATUS \r
79GetNicName (\r
68074260 80 IN EFI_HANDLE ControllerHandle,\r
a0f2af3a 81 IN UINTN NicNumber,\r
68074260
RC
82 OUT CHAR16 *NicName\r
83 );\r
84\r
0fcf66a4
QS
85/**\r
86 Create a child for the service identified by its service binding protocol GUID\r
87 and get from the child the interface of the protocol identified by its GUID.\r
88\r
89 @param[in] ControllerHandle Controller handle.\r
90 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the\r
91 service to be created.\r
92 @param[in] ProtocolGuid GUID of the protocol to be open.\r
93 @param[out] ChildHandle Address where the handler of the\r
94 created child is returned. NULL is\r
95 returned in case of error.\r
96 @param[out] Interface Address where a pointer to the\r
97 protocol interface is returned in\r
98 case of success.\r
99\r
100 @return EFI_SUCCESS The child was created and the protocol opened.\r
101 @return Others Either the creation of the child or the opening\r
102 of the protocol failed.\r
103**/\r
104STATIC \r
105EFI_STATUS \r
106CreateServiceChildAndOpenProtocol (\r
68074260
RC
107 IN EFI_HANDLE ControllerHandle,\r
108 IN EFI_GUID *ServiceBindingProtocolGuid,\r
109 IN EFI_GUID *ProtocolGuid,\r
110 OUT EFI_HANDLE *ChildHandle,\r
111 OUT VOID **Interface\r
112 );\r
113\r
0fcf66a4
QS
114/**\r
115 Close the protocol identified by its GUID on the child handle of the service\r
116 identified by its service binding protocol GUID, then destroy the child\r
117 handle.\r
118\r
119 @param[in] ControllerHandle Controller handle.\r
120 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the\r
121 service to be destroyed.\r
122 @param[in] ProtocolGuid GUID of the protocol to be closed.\r
123 @param[in] ChildHandle Handle of the child to be destroyed.\r
124\r
125**/\r
126STATIC \r
127VOID \r
128CloseProtocolAndDestroyServiceChild (\r
68074260
RC
129 IN EFI_HANDLE ControllerHandle,\r
130 IN EFI_GUID *ServiceBindingProtocolGuid,\r
131 IN EFI_GUID *ProtocolGuid,\r
132 IN EFI_HANDLE ChildHandle\r
133 );\r
134\r
0fcf66a4
QS
135/**\r
136 Worker function that gets the size in numbers of bytes of a file from a TFTP\r
137 server before to download the file.\r
138\r
139 @param[in] Mtftp4 MTFTP4 protocol interface\r
140 @param[in] FilePath Path of the file, ASCII encoded\r
141 @param[out] FileSize Address where to store the file size in number of\r
142 bytes.\r
143\r
144 @retval EFI_SUCCESS The size of the file was returned.\r
145 @retval EFI_UNSUPPORTED The server does not support the "tsize" option.\r
146 @retval Others Error when retrieving the information from the server\r
147 (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)\r
148 or error when parsing the response of the server.\r
149**/\r
150STATIC \r
151EFI_STATUS \r
152GetFileSize (\r
68074260
RC
153 IN EFI_MTFTP4_PROTOCOL *Mtftp4,\r
154 IN CONST CHAR8 *FilePath,\r
155 OUT UINTN *FileSize\r
156 );\r
157\r
0fcf66a4
QS
158/**\r
159 Worker function that download the data of a file from a TFTP server given\r
160 the path of the file and its size.\r
161\r
162 @param[in] Mtftp4 MTFTP4 protocol interface\r
163 @param[in] FilePath Path of the file, Unicode encoded\r
164 @param[in] AsciiFilePath Path of the file, ASCII encoded\r
165 @param[in] FileSize Size of the file in number of bytes\r
166 @param[out] Data Address where to store the address of the buffer\r
167 where the data of the file were downloaded in\r
168 case of success.\r
169\r
170 @retval EFI_SUCCESS The file was downloaded.\r
171 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
172 @retval Others The downloading of the file from the server failed\r
173 (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).\r
174\r
175**/\r
176STATIC \r
177EFI_STATUS \r
178DownloadFile (\r
68074260
RC
179 IN EFI_MTFTP4_PROTOCOL *Mtftp4,\r
180 IN CONST CHAR16 *FilePath,\r
181 IN CONST CHAR8 *AsciiFilePath,\r
182 IN UINTN FileSize,\r
183 OUT VOID **Data\r
184 );\r
185\r
0fcf66a4
QS
186/**\r
187 Update the progress of a file download\r
188 This procedure is called each time a new TFTP packet is received.\r
189\r
190 @param[in] This MTFTP4 protocol interface\r
191 @param[in] Token Parameters for the download of the file\r
192 @param[in] PacketLen Length of the packet\r
193 @param[in] Packet Address of the packet\r
194\r
195 @retval EFI_SUCCESS All packets are accepted.\r
196\r
197**/\r
198STATIC \r
199EFI_STATUS \r
7367e66f 200EFIAPI\r
0fcf66a4 201CheckPacket (\r
68074260
RC
202 IN EFI_MTFTP4_PROTOCOL *This,\r
203 IN EFI_MTFTP4_TOKEN *Token,\r
204 IN UINT16 PacketLen,\r
205 IN EFI_MTFTP4_PACKET *Packet\r
206 );\r
207\r
208EFI_MTFTP4_CONFIG_DATA DefaultMtftp4ConfigData = {\r
209 TRUE, // Use default setting\r
210 { { 0, 0, 0, 0 } }, // StationIp - Not relevant as UseDefaultSetting=TRUE\r
211 { { 0, 0, 0, 0 } }, // SubnetMask - Not relevant as UseDefaultSetting=TRUE\r
212 0, // LocalPort - Automatically assigned port number.\r
213 { { 0, 0, 0, 0 } }, // GatewayIp - Not relevant as UseDefaultSetting=TRUE\r
214 { { 0, 0, 0, 0 } }, // ServerIp - Not known yet\r
215 69, // InitialServerPort - Standard TFTP server port\r
216 6, // TryCount - Max number of retransmissions.\r
217 4 // TimeoutValue - Retransmission timeout in seconds.\r
218};\r
219\r
220STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
221 {L"-i", TypeValue},\r
222 {L"-l", TypeValue},\r
223 {L"-r", TypeValue},\r
224 {L"-c", TypeValue},\r
225 {L"-t", TypeValue},\r
226 {NULL , TypeMax}\r
227 };\r
228\r
229/**\r
230 Function for 'tftp' command.\r
231\r
232 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
233 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
234\r
235 @return SHELL_SUCCESS The 'tftp' command completed successfully.\r
236 @return SHELL_ABORTED The Shell Library initialization failed.\r
237 @return SHELL_INVALID_PARAMETER At least one of the command's arguments is\r
238 not valid.\r
239 @return SHELL_OUT_OF_RESOURCES A memory allocation failed.\r
240 @return SHELL_NOT_FOUND Network Interface Card not found or server\r
241 error or file error.\r
242\r
243**/\r
244SHELL_STATUS\r
245EFIAPI\r
246ShellCommandRunTftp (\r
247 IN EFI_HANDLE ImageHandle,\r
248 IN EFI_SYSTEM_TABLE *SystemTable\r
249 )\r
250{\r
251 SHELL_STATUS ShellStatus;\r
252 EFI_STATUS Status;\r
253 LIST_ENTRY *CheckPackage;\r
254 CHAR16 *ProblemParam;\r
255 UINTN ParamCount;\r
256 CONST CHAR16 *UserNicName;\r
257 BOOLEAN NicFound;\r
258 CONST CHAR16 *ValueStr;\r
259 CONST CHAR16 *RemoteFilePath;\r
260 CHAR8 *AsciiRemoteFilePath;\r
261 CONST CHAR16 *Walker;\r
262 CONST CHAR16 *LocalFilePath;\r
263 EFI_MTFTP4_CONFIG_DATA Mtftp4ConfigData;\r
264 EFI_HANDLE *Handles;\r
265 UINTN HandleCount;\r
266 UINTN NicNumber;\r
6add86ab 267 CHAR16 NicName[IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH];\r
68074260
RC
268 EFI_HANDLE ControllerHandle;\r
269 EFI_HANDLE Mtftp4ChildHandle;\r
270 EFI_MTFTP4_PROTOCOL *Mtftp4;\r
271 UINTN FileSize;\r
272 VOID *Data;\r
273 SHELL_FILE_HANDLE FileHandle;\r
274\r
275 ShellStatus = SHELL_INVALID_PARAMETER;\r
276 ProblemParam = NULL;\r
277 NicFound = FALSE;\r
278 AsciiRemoteFilePath = NULL;\r
279 Handles = NULL;\r
6add86ab 280 FileSize = 0;\r
68074260
RC
281\r
282 //\r
283 // Initialize the Shell library (we must be in non-auto-init...)\r
284 //\r
285 Status = ShellInitialize ();\r
286 if (EFI_ERROR (Status)) {\r
287 ASSERT_EFI_ERROR (Status);\r
288 return SHELL_ABORTED;\r
289 }\r
290\r
291 //\r
292 // Parse the command line.\r
293 //\r
294 Status = ShellCommandLineParse (ParamList, &CheckPackage, &ProblemParam, TRUE);\r
295 if (EFI_ERROR (Status)) {\r
296 if ((Status == EFI_VOLUME_CORRUPTED) &&\r
297 (ProblemParam != NULL) ) {\r
298 ShellPrintHiiEx (\r
299 -1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellTftpHiiHandle,\r
300 L"tftp", ProblemParam\r
301 );\r
302 FreePool (ProblemParam);\r
303 } else {\r
304 ASSERT (FALSE);\r
305 }\r
306 goto Error;\r
307 }\r
308\r
309 //\r
310 // Check the number of parameters\r
311 //\r
312 ParamCount = ShellCommandLineGetCount (CheckPackage);\r
313 if (ParamCount > 4) {\r
314 ShellPrintHiiEx (\r
315 -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY),\r
316 gShellTftpHiiHandle, L"tftp"\r
317 );\r
318 goto Error;\r
319 }\r
320 if (ParamCount < 3) {\r
321 ShellPrintHiiEx (\r
322 -1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW),\r
323 gShellTftpHiiHandle, L"tftp"\r
324 );\r
325 goto Error;\r
326 }\r
327\r
328 Mtftp4ConfigData = DefaultMtftp4ConfigData;\r
329\r
330 //\r
331 // Check the host IPv4 address\r
332 //\r
333 ValueStr = ShellCommandLineGetRawValue (CheckPackage, 1);\r
334 Status = NetLibStrToIp4 (ValueStr, &Mtftp4ConfigData.ServerIp);\r
335 if (EFI_ERROR (Status)) {\r
336 ShellPrintHiiEx (\r
337 -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),\r
338 gShellTftpHiiHandle, L"tftp", ValueStr\r
339 );\r
340 goto Error;\r
341 }\r
342\r
343 RemoteFilePath = ShellCommandLineGetRawValue (CheckPackage, 2);\r
c6173804 344 ASSERT(RemoteFilePath != NULL);\r
68074260
RC
345 AsciiRemoteFilePath = AllocatePool (\r
346 (StrLen (RemoteFilePath) + 1) * sizeof (CHAR8)\r
347 );\r
348 if (AsciiRemoteFilePath == NULL) {\r
349 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
350 goto Error;\r
351 }\r
352 UnicodeStrToAsciiStr (RemoteFilePath, AsciiRemoteFilePath);\r
353\r
354 if (ParamCount == 4) {\r
355 LocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3);\r
356 } else {\r
357 Walker = RemoteFilePath + StrLen (RemoteFilePath);\r
358 while ((--Walker) >= RemoteFilePath) {\r
359 if ((*Walker == L'\\') ||\r
360 (*Walker == L'/' ) ) {\r
361 break;\r
362 }\r
363 }\r
364 LocalFilePath = Walker + 1;\r
365 }\r
366\r
367 //\r
368 // Get the name of the Network Interface Card to be used if any.\r
369 //\r
370 UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i");\r
371\r
372 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l");\r
373 if (ValueStr != NULL) {\r
374 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.LocalPort)) {\r
375 goto Error;\r
376 }\r
377 }\r
378\r
379 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-r");\r
380 if (ValueStr != NULL) {\r
381 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.InitialServerPort)) {\r
382 goto Error;\r
383 }\r
384 }\r
385\r
386 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-c");\r
387 if (ValueStr != NULL) {\r
388 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TryCount)) {\r
389 goto Error;\r
390 }\r
391 }\r
392\r
393 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t");\r
394 if (ValueStr != NULL) {\r
395 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TimeoutValue)) {\r
396 goto Error;\r
397 }\r
398 if (Mtftp4ConfigData.TimeoutValue == 0) {\r
399 ShellPrintHiiEx (\r
400 -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),\r
401 gShellTftpHiiHandle, L"tftp", ValueStr\r
402 );\r
403 goto Error;\r
404 }\r
405 }\r
406\r
407 //\r
408 // Locate all MTFTP4 Service Binding protocols\r
409 //\r
410 ShellStatus = SHELL_NOT_FOUND;\r
411 Status = gBS->LocateHandleBuffer (\r
412 ByProtocol,\r
413 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
414 NULL,\r
415 &HandleCount,\r
416 &Handles\r
417 );\r
418 if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
419 ShellPrintHiiEx (\r
420 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NO_NIC),\r
421 gShellTftpHiiHandle\r
422 );\r
423 goto Error;\r
424 }\r
425\r
426 for (NicNumber = 0;\r
427 (NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS);\r
428 NicNumber++) {\r
429 ControllerHandle = Handles[NicNumber];\r
430 Data = NULL;\r
431\r
432 Status = GetNicName (ControllerHandle, NicNumber, NicName);\r
433 if (EFI_ERROR (Status)) {\r
434 ShellPrintHiiEx (\r
435 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME),\r
436 gShellTftpHiiHandle, NicNumber, Status\r
437 );\r
438 continue;\r
439 }\r
440\r
441 if (UserNicName != NULL) {\r
442 if (StrCmp (NicName, UserNicName) != 0) {\r
443 continue;\r
444 }\r
445 NicFound = TRUE;\r
446 }\r
447\r
448 Status = CreateServiceChildAndOpenProtocol (\r
449 ControllerHandle,\r
450 &gEfiMtftp4ServiceBindingProtocolGuid,\r
451 &gEfiMtftp4ProtocolGuid,\r
452 &Mtftp4ChildHandle,\r
453 (VOID**)&Mtftp4\r
454 );\r
455 if (EFI_ERROR (Status)) {\r
456 ShellPrintHiiEx (\r
457 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL),\r
458 gShellTftpHiiHandle, NicName, Status\r
459 );\r
460 continue;\r
461 }\r
462\r
463 Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData);\r
464 if (EFI_ERROR (Status)) {\r
465 ShellPrintHiiEx (\r
466 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE),\r
467 gShellTftpHiiHandle, NicName, Status\r
468 );\r
469 goto NextHandle;\r
470 }\r
471\r
472 Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize);\r
473 if (EFI_ERROR (Status)) {\r
474 ShellPrintHiiEx (\r
475 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE),\r
476 gShellTftpHiiHandle, RemoteFilePath, NicName, Status\r
477 );\r
478 goto NextHandle;\r
479 }\r
480\r
481 Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, FileSize, &Data);\r
482 if (EFI_ERROR (Status)) {\r
483 ShellPrintHiiEx (\r
484 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD),\r
485 gShellTftpHiiHandle, RemoteFilePath, NicName, Status\r
486 );\r
487 goto NextHandle;\r
488 }\r
489\r
490 if (!EFI_ERROR (ShellFileExists (LocalFilePath))) {\r
491 ShellDeleteFileByName (LocalFilePath);\r
492 }\r
493\r
494 Status = ShellOpenFileByName (\r
495 LocalFilePath,\r
496 &FileHandle,\r
497 EFI_FILE_MODE_CREATE |\r
498 EFI_FILE_MODE_WRITE |\r
499 EFI_FILE_MODE_READ,\r
500 0\r
501 );\r
502 if (EFI_ERROR (Status)) {\r
503 ShellPrintHiiEx (\r
504 -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL),\r
505 gShellTftpHiiHandle, L"tftp", LocalFilePath\r
506 );\r
507 goto NextHandle;\r
508 }\r
509\r
510 Status = ShellWriteFile (FileHandle, &FileSize, Data);\r
511 if (!EFI_ERROR (Status)) {\r
512 ShellStatus = SHELL_SUCCESS;\r
513 } else {\r
514 ShellPrintHiiEx (\r
515 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE),\r
516 gShellTftpHiiHandle, LocalFilePath, Status\r
517 );\r
518 }\r
519 ShellCloseFile (&FileHandle);\r
520\r
521 NextHandle:\r
522\r
523 if (Data != NULL) {\r
524 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Data, EFI_SIZE_TO_PAGES (FileSize));\r
525 }\r
526\r
527 CloseProtocolAndDestroyServiceChild (\r
528 ControllerHandle,\r
529 &gEfiMtftp4ServiceBindingProtocolGuid,\r
530 &gEfiMtftp4ProtocolGuid,\r
531 Mtftp4ChildHandle\r
532 );\r
533 }\r
534\r
a0f2af3a 535 if ((UserNicName != NULL) && (!NicFound)) {\r
68074260
RC
536 ShellPrintHiiEx (\r
537 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND),\r
538 gShellTftpHiiHandle, UserNicName\r
539 );\r
540 }\r
541\r
542 Error:\r
543\r
544 ShellCommandLineFreeVarList (CheckPackage);\r
545 if (AsciiRemoteFilePath != NULL) {\r
546 FreePool (AsciiRemoteFilePath);\r
547 }\r
548 if (Handles != NULL) {\r
549 FreePool (Handles);\r
550 }\r
551\r
552 return ShellStatus;\r
553}\r
554\r
555/**\r
556 Check and convert the UINT16 option values of the 'tftp' command\r
557\r
558 @param[in] ValueStr Value as an Unicode encoded string\r
559 @param[out] Value UINT16 value\r
560\r
561 @return TRUE The value was returned.\r
562 @return FALSE A parsing error occured.\r
563**/\r
564STATIC\r
565BOOLEAN\r
566StringToUint16 (\r
567 IN CONST CHAR16 *ValueStr,\r
568 OUT UINT16 *Value\r
569 )\r
570{\r
571 UINTN Val;\r
572\r
573 Val = ShellStrToUintn (ValueStr);\r
574 if (Val > MAX_UINT16) {\r
575 ShellPrintHiiEx (\r
576 -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),\r
577 gShellTftpHiiHandle, L"tftp", ValueStr\r
578 );\r
579 return FALSE;\r
580 }\r
581\r
6add86ab 582 *Value = (UINT16)Val;\r
68074260
RC
583 return TRUE;\r
584}\r
585\r
586/**\r
587 Get the name of the NIC.\r
588\r
589 @param[in] ControllerHandle The network physical device handle.\r
590 @param[in] NicNumber The network physical device number.\r
591 @param[out] NicName Address where to store the NIC name.\r
592 The memory area has to be at least\r
6add86ab
JC
593 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH \r
594 double byte wide.\r
68074260
RC
595\r
596 @return EFI_SUCCESS The name of the NIC was returned.\r
597 @return Others The creation of the child for the Managed\r
598 Network Service failed or the opening of\r
599 the Managed Network Protocol failed or\r
600 the operational parameters for the\r
601 Managed Network Protocol could not be\r
602 read.\r
603**/\r
604STATIC\r
605EFI_STATUS\r
606GetNicName (\r
607 IN EFI_HANDLE ControllerHandle,\r
608 IN UINTN NicNumber,\r
609 OUT CHAR16 *NicName\r
610 )\r
611{\r
612 EFI_STATUS Status;\r
613 EFI_HANDLE MnpHandle;\r
614 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
615 EFI_SIMPLE_NETWORK_MODE SnpMode;\r
616\r
617 Status = CreateServiceChildAndOpenProtocol (\r
618 ControllerHandle,\r
619 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
620 &gEfiManagedNetworkProtocolGuid,\r
621 &MnpHandle,\r
622 (VOID**)&Mnp\r
623 );\r
624 if (EFI_ERROR (Status)) {\r
625 goto Error;\r
626 }\r
627\r
628 Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);\r
629 if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
630 goto Error;\r
631 }\r
632\r
633 UnicodeSPrint (\r
634 NicName,\r
6add86ab 635 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH,\r
68074260
RC
636 SnpMode.IfType == NET_IFTYPE_ETHERNET ?\r
637 L"eth%d" :\r
638 L"unk%d" ,\r
639 NicNumber\r
640 );\r
641\r
642 Status = EFI_SUCCESS;\r
643\r
644Error:\r
645\r
646 if (MnpHandle != NULL) {\r
647 CloseProtocolAndDestroyServiceChild (\r
648 ControllerHandle,\r
649 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
650 &gEfiManagedNetworkProtocolGuid,\r
651 MnpHandle\r
652 );\r
653 }\r
654\r
655 return Status;\r
656}\r
657\r
658/**\r
659 Create a child for the service identified by its service binding protocol GUID\r
660 and get from the child the interface of the protocol identified by its GUID.\r
661\r
662 @param[in] ControllerHandle Controller handle.\r
663 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the\r
664 service to be created.\r
665 @param[in] ProtocolGuid GUID of the protocol to be open.\r
666 @param[out] ChildHandle Address where the handler of the\r
667 created child is returned. NULL is\r
668 returned in case of error.\r
669 @param[out] Interface Address where a pointer to the\r
670 protocol interface is returned in\r
671 case of success.\r
672\r
673 @return EFI_SUCCESS The child was created and the protocol opened.\r
674 @return Others Either the creation of the child or the opening\r
675 of the protocol failed.\r
676**/\r
677STATIC\r
678EFI_STATUS\r
679CreateServiceChildAndOpenProtocol (\r
680 IN EFI_HANDLE ControllerHandle,\r
681 IN EFI_GUID *ServiceBindingProtocolGuid,\r
682 IN EFI_GUID *ProtocolGuid,\r
683 OUT EFI_HANDLE *ChildHandle,\r
684 OUT VOID **Interface\r
685 )\r
686{\r
687 EFI_STATUS Status;\r
688\r
689 *ChildHandle = NULL;\r
690 Status = NetLibCreateServiceChild (\r
691 ControllerHandle,\r
692 gImageHandle,\r
693 ServiceBindingProtocolGuid,\r
694 ChildHandle\r
695 );\r
696 if (!EFI_ERROR (Status)) {\r
697 Status = gBS->OpenProtocol (\r
698 *ChildHandle,\r
699 ProtocolGuid,\r
700 Interface,\r
701 gImageHandle,\r
702 ControllerHandle,\r
703 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
704 );\r
705 if (EFI_ERROR (Status)) {\r
706 NetLibDestroyServiceChild (\r
707 ControllerHandle,\r
708 gImageHandle,\r
709 ServiceBindingProtocolGuid,\r
710 *ChildHandle\r
711 );\r
712 *ChildHandle = NULL;\r
713 }\r
714 }\r
715\r
716 return Status;\r
717}\r
718\r
719/**\r
720 Close the protocol identified by its GUID on the child handle of the service\r
721 identified by its service binding protocol GUID, then destroy the child\r
722 handle.\r
723\r
724 @param[in] ControllerHandle Controller handle.\r
725 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the\r
726 service to be destroyed.\r
727 @param[in] ProtocolGuid GUID of the protocol to be closed.\r
728 @param[in] ChildHandle Handle of the child to be destroyed.\r
729\r
730**/\r
731STATIC\r
732VOID\r
733CloseProtocolAndDestroyServiceChild (\r
734 IN EFI_HANDLE ControllerHandle,\r
735 IN EFI_GUID *ServiceBindingProtocolGuid,\r
736 IN EFI_GUID *ProtocolGuid,\r
737 IN EFI_HANDLE ChildHandle\r
738 )\r
739{\r
740 gBS->CloseProtocol (\r
741 ChildHandle,\r
742 ProtocolGuid,\r
743 gImageHandle,\r
744 ControllerHandle\r
745 );\r
746\r
747 NetLibDestroyServiceChild (\r
748 ControllerHandle,\r
749 gImageHandle,\r
750 ServiceBindingProtocolGuid,\r
751 ChildHandle\r
752 );\r
753}\r
754\r
755/**\r
756 Worker function that gets the size in numbers of bytes of a file from a TFTP\r
757 server before to download the file.\r
758\r
759 @param[in] Mtftp4 MTFTP4 protocol interface\r
760 @param[in] FilePath Path of the file, ASCII encoded\r
761 @param[out] FileSize Address where to store the file size in number of\r
762 bytes.\r
763\r
764 @retval EFI_SUCCESS The size of the file was returned.\r
765 @retval EFI_UNSUPPORTED The server does not support the "tsize" option.\r
766 @retval Others Error when retrieving the information from the server\r
767 (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)\r
768 or error when parsing the response of the server.\r
769**/\r
770STATIC\r
771EFI_STATUS\r
772GetFileSize (\r
773 IN EFI_MTFTP4_PROTOCOL *Mtftp4,\r
774 IN CONST CHAR8 *FilePath,\r
775 OUT UINTN *FileSize\r
776 )\r
777{\r
778 EFI_STATUS Status;\r
779 EFI_MTFTP4_OPTION ReqOpt[1];\r
780 EFI_MTFTP4_PACKET *Packet;\r
781 UINT32 PktLen;\r
782 EFI_MTFTP4_OPTION *TableOfOptions;\r
783 EFI_MTFTP4_OPTION *Option;\r
784 UINT32 OptCnt;\r
785 UINT8 OptBuf[128];\r
786\r
787 ReqOpt[0].OptionStr = (UINT8*)"tsize";\r
788 OptBuf[0] = '0';\r
789 OptBuf[1] = 0;\r
790 ReqOpt[0].ValueStr = OptBuf;\r
791\r
792 Status = Mtftp4->GetInfo (\r
793 Mtftp4,\r
794 NULL,\r
795 (UINT8*)FilePath,\r
796 NULL,\r
797 1,\r
798 ReqOpt,\r
799 &PktLen,\r
800 &Packet\r
801 );\r
802\r
803 if (EFI_ERROR (Status)) {\r
804 goto Error;\r
805 }\r
806\r
807 Status = Mtftp4->ParseOptions (\r
808 Mtftp4,\r
809 PktLen,\r
810 Packet,\r
811 (UINT32 *) &OptCnt,\r
812 &TableOfOptions\r
813 );\r
814 if (EFI_ERROR (Status)) {\r
815 goto Error;\r
816 }\r
817\r
818 Option = TableOfOptions;\r
819 while (OptCnt != 0) {\r
820 if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {\r
821 *FileSize = AsciiStrDecimalToUintn ((CHAR8 *)Option->ValueStr);\r
822 break;\r
823 }\r
824 OptCnt--;\r
825 Option++;\r
826 }\r
827 FreePool (TableOfOptions);\r
828\r
829 if (OptCnt == 0) {\r
830 Status = EFI_UNSUPPORTED;\r
831 }\r
832\r
833Error :\r
834\r
835 return Status;\r
836}\r
837\r
838/**\r
839 Worker function that download the data of a file from a TFTP server given\r
840 the path of the file and its size.\r
841\r
842 @param[in] Mtftp4 MTFTP4 protocol interface\r
843 @param[in] FilePath Path of the file, Unicode encoded\r
844 @param[in] AsciiFilePath Path of the file, ASCII encoded\r
845 @param[in] FileSize Size of the file in number of bytes\r
846 @param[out] Data Address where to store the address of the buffer\r
847 where the data of the file were downloaded in\r
848 case of success.\r
849\r
850 @retval EFI_SUCCESS The file was downloaded.\r
851 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
852 @retval Others The downloading of the file from the server failed\r
853 (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).\r
854\r
855**/\r
856STATIC\r
857EFI_STATUS\r
858DownloadFile (\r
859 IN EFI_MTFTP4_PROTOCOL *Mtftp4,\r
860 IN CONST CHAR16 *FilePath,\r
861 IN CONST CHAR8 *AsciiFilePath,\r
862 IN UINTN FileSize,\r
863 OUT VOID **Data\r
864 )\r
865{\r
866 EFI_STATUS Status;\r
867 EFI_PHYSICAL_ADDRESS PagesAddress;\r
868 VOID *Buffer;\r
869 DOWNLOAD_CONTEXT *TftpContext;\r
870 EFI_MTFTP4_TOKEN Mtftp4Token;\r
871\r
872 // Downloaded file can be large. BS.AllocatePages() is more faster\r
873 // than AllocatePool() and avoid fragmentation.\r
874 // The downloaded file could be an EFI application. Marking the\r
875 // allocated page as EfiBootServicesCode would allow to execute a\r
876 // potential downloaded EFI application.\r
877 Status = gBS->AllocatePages (\r
878 AllocateAnyPages,\r
879 EfiBootServicesCode,\r
880 EFI_SIZE_TO_PAGES (FileSize),\r
881 &PagesAddress\r
882 );\r
883 if (EFI_ERROR (Status)) {\r
884 return Status;\r
885 }\r
886\r
887 Buffer = (VOID*)(UINTN)PagesAddress;\r
888 TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT));\r
889 if (TftpContext == NULL) {\r
890 Status = EFI_OUT_OF_RESOURCES;\r
891 goto Error;\r
892 }\r
893 TftpContext->FileSize = FileSize;\r
894 TftpContext->DownloadedNbOfBytes = 0;\r
895 TftpContext->LastReportedNbOfBytes = 0;\r
896\r
897 ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));\r
898 Mtftp4Token.Filename = (UINT8*)AsciiFilePath;\r
899 Mtftp4Token.BufferSize = FileSize;\r
900 Mtftp4Token.Buffer = Buffer;\r
901 Mtftp4Token.CheckPacket = CheckPacket;\r
902 Mtftp4Token.Context = (VOID*)TftpContext;\r
903\r
904 ShellPrintHiiEx (\r
905 -1, -1, NULL, STRING_TOKEN (STR_TFTP_DOWNLOADING),\r
906 gShellTftpHiiHandle, FilePath\r
907 );\r
908\r
909 Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);\r
910 ShellPrintHiiEx (\r
911 -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF),\r
912 gShellTftpHiiHandle\r
913 );\r
914\r
915Error :\r
916\r
917 if (TftpContext == NULL) {\r
918 FreePool (TftpContext);\r
919 }\r
920\r
921 if (EFI_ERROR (Status)) {\r
922 gBS->FreePages (PagesAddress, EFI_SIZE_TO_PAGES (FileSize));\r
923 return Status;\r
924 }\r
925\r
926 *Data = Buffer;\r
927\r
928 return EFI_SUCCESS;\r
929}\r
930\r
931/**\r
932 Update the progress of a file download\r
933 This procedure is called each time a new TFTP packet is received.\r
934\r
935 @param[in] This MTFTP4 protocol interface\r
936 @param[in] Token Parameters for the download of the file\r
937 @param[in] PacketLen Length of the packet\r
938 @param[in] Packet Address of the packet\r
939\r
940 @retval EFI_SUCCESS All packets are accepted.\r
941\r
942**/\r
943STATIC\r
944EFI_STATUS\r
7367e66f 945EFIAPI\r
68074260
RC
946CheckPacket (\r
947 IN EFI_MTFTP4_PROTOCOL *This,\r
948 IN EFI_MTFTP4_TOKEN *Token,\r
949 IN UINT16 PacketLen,\r
950 IN EFI_MTFTP4_PACKET *Packet\r
951 )\r
952{\r
953 DOWNLOAD_CONTEXT *Context;\r
954 CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE];\r
6add86ab 955 UINTN NbOfKb;\r
68074260 956 UINTN Index;\r
310b053a
JC
957 UINTN LastStep;\r
958 UINTN Step;\r
da6b8feb 959 EFI_STATUS Status;\r
68074260
RC
960\r
961 if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) {\r
962 return EFI_SUCCESS;\r
963 }\r
964\r
965 Context = (DOWNLOAD_CONTEXT*)Token->Context;\r
966 if (Context->DownloadedNbOfBytes == 0) {\r
967 ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame);\r
968 }\r
969\r
970 //\r
971 // The data in the packet are prepended with two UINT16 :\r
972 // . OpCode = EFI_MTFTP4_OPCODE_DATA\r
973 // . Block = the number of this block of data\r
974 //\r
975 Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode)\r
976 - sizeof (Packet->Data.Block);\r
977 NbOfKb = Context->DownloadedNbOfBytes / 1024;\r
978\r
979 Progress[0] = L'\0';\r
6add86ab
JC
980 LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;\r
981 Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;\r
982\r
68074260
RC
983 if (Step <= LastStep) {\r
984 return EFI_SUCCESS;\r
985 }\r
986\r
987 ShellPrintEx (-1, -1, L"%s", mTftpProgressDelete);\r
988\r
da6b8feb
QS
989 Status = StrCpyS (Progress, TFTP_PROGRESS_MESSAGE_SIZE, mTftpProgressFrame);\r
990 if (EFI_ERROR(Status)) {\r
991 return Status;\r
992 }\r
68074260
RC
993 for (Index = 1; Index < Step; Index++) {\r
994 Progress[Index] = L'=';\r
995 }\r
996 Progress[Step] = L'>';\r
997\r
998 UnicodeSPrint (\r
999 Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,\r
1000 sizeof (Progress) - sizeof (mTftpProgressFrame),\r
1001 L" %7d Kb",\r
1002 NbOfKb\r
1003 );\r
1004 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;\r
1005\r
1006 ShellPrintEx (-1, -1, L"%s", Progress);\r
1007\r
1008 return EFI_SUCCESS;\r
1009}\r