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