]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellTftpCommandLib/Tftp.c
ShellPkg: UefiShellTftpCommandLib: fix incompatible pointer assignment
[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
344 AsciiRemoteFilePath = AllocatePool (\r
345 (StrLen (RemoteFilePath) + 1) * sizeof (CHAR8)\r
346 );\r
347 if (AsciiRemoteFilePath == NULL) {\r
348 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
349 goto Error;\r
350 }\r
351 UnicodeStrToAsciiStr (RemoteFilePath, AsciiRemoteFilePath);\r
352\r
353 if (ParamCount == 4) {\r
354 LocalFilePath = ShellCommandLineGetRawValue (CheckPackage, 3);\r
355 } else {\r
356 Walker = RemoteFilePath + StrLen (RemoteFilePath);\r
357 while ((--Walker) >= RemoteFilePath) {\r
358 if ((*Walker == L'\\') ||\r
359 (*Walker == L'/' ) ) {\r
360 break;\r
361 }\r
362 }\r
363 LocalFilePath = Walker + 1;\r
364 }\r
365\r
366 //\r
367 // Get the name of the Network Interface Card to be used if any.\r
368 //\r
369 UserNicName = ShellCommandLineGetValue (CheckPackage, L"-i");\r
370\r
371 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-l");\r
372 if (ValueStr != NULL) {\r
373 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.LocalPort)) {\r
374 goto Error;\r
375 }\r
376 }\r
377\r
378 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-r");\r
379 if (ValueStr != NULL) {\r
380 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.InitialServerPort)) {\r
381 goto Error;\r
382 }\r
383 }\r
384\r
385 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-c");\r
386 if (ValueStr != NULL) {\r
387 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TryCount)) {\r
388 goto Error;\r
389 }\r
390 }\r
391\r
392 ValueStr = ShellCommandLineGetValue (CheckPackage, L"-t");\r
393 if (ValueStr != NULL) {\r
394 if (!StringToUint16 (ValueStr, &Mtftp4ConfigData.TimeoutValue)) {\r
395 goto Error;\r
396 }\r
397 if (Mtftp4ConfigData.TimeoutValue == 0) {\r
398 ShellPrintHiiEx (\r
399 -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),\r
400 gShellTftpHiiHandle, L"tftp", ValueStr\r
401 );\r
402 goto Error;\r
403 }\r
404 }\r
405\r
406 //\r
407 // Locate all MTFTP4 Service Binding protocols\r
408 //\r
409 ShellStatus = SHELL_NOT_FOUND;\r
410 Status = gBS->LocateHandleBuffer (\r
411 ByProtocol,\r
412 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
413 NULL,\r
414 &HandleCount,\r
415 &Handles\r
416 );\r
417 if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
418 ShellPrintHiiEx (\r
419 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NO_NIC),\r
420 gShellTftpHiiHandle\r
421 );\r
422 goto Error;\r
423 }\r
424\r
425 for (NicNumber = 0;\r
426 (NicNumber < HandleCount) && (ShellStatus != SHELL_SUCCESS);\r
427 NicNumber++) {\r
428 ControllerHandle = Handles[NicNumber];\r
429 Data = NULL;\r
430\r
431 Status = GetNicName (ControllerHandle, NicNumber, NicName);\r
432 if (EFI_ERROR (Status)) {\r
433 ShellPrintHiiEx (\r
434 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NAME),\r
435 gShellTftpHiiHandle, NicNumber, Status\r
436 );\r
437 continue;\r
438 }\r
439\r
440 if (UserNicName != NULL) {\r
441 if (StrCmp (NicName, UserNicName) != 0) {\r
442 continue;\r
443 }\r
444 NicFound = TRUE;\r
445 }\r
446\r
447 Status = CreateServiceChildAndOpenProtocol (\r
448 ControllerHandle,\r
449 &gEfiMtftp4ServiceBindingProtocolGuid,\r
450 &gEfiMtftp4ProtocolGuid,\r
451 &Mtftp4ChildHandle,\r
452 (VOID**)&Mtftp4\r
453 );\r
454 if (EFI_ERROR (Status)) {\r
455 ShellPrintHiiEx (\r
456 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_OPEN_PROTOCOL),\r
457 gShellTftpHiiHandle, NicName, Status\r
458 );\r
459 continue;\r
460 }\r
461\r
462 Status = Mtftp4->Configure (Mtftp4, &Mtftp4ConfigData);\r
463 if (EFI_ERROR (Status)) {\r
464 ShellPrintHiiEx (\r
465 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_CONFIGURE),\r
466 gShellTftpHiiHandle, NicName, Status\r
467 );\r
468 goto NextHandle;\r
469 }\r
470\r
471 Status = GetFileSize (Mtftp4, AsciiRemoteFilePath, &FileSize);\r
472 if (EFI_ERROR (Status)) {\r
473 ShellPrintHiiEx (\r
474 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_FILE_SIZE),\r
475 gShellTftpHiiHandle, RemoteFilePath, NicName, Status\r
476 );\r
477 goto NextHandle;\r
478 }\r
479\r
480 Status = DownloadFile (Mtftp4, RemoteFilePath, AsciiRemoteFilePath, FileSize, &Data);\r
481 if (EFI_ERROR (Status)) {\r
482 ShellPrintHiiEx (\r
483 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_DOWNLOAD),\r
484 gShellTftpHiiHandle, RemoteFilePath, NicName, Status\r
485 );\r
486 goto NextHandle;\r
487 }\r
488\r
489 if (!EFI_ERROR (ShellFileExists (LocalFilePath))) {\r
490 ShellDeleteFileByName (LocalFilePath);\r
491 }\r
492\r
493 Status = ShellOpenFileByName (\r
494 LocalFilePath,\r
495 &FileHandle,\r
496 EFI_FILE_MODE_CREATE |\r
497 EFI_FILE_MODE_WRITE |\r
498 EFI_FILE_MODE_READ,\r
499 0\r
500 );\r
501 if (EFI_ERROR (Status)) {\r
502 ShellPrintHiiEx (\r
503 -1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL),\r
504 gShellTftpHiiHandle, L"tftp", LocalFilePath\r
505 );\r
506 goto NextHandle;\r
507 }\r
508\r
509 Status = ShellWriteFile (FileHandle, &FileSize, Data);\r
510 if (!EFI_ERROR (Status)) {\r
511 ShellStatus = SHELL_SUCCESS;\r
512 } else {\r
513 ShellPrintHiiEx (\r
514 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_WRITE),\r
515 gShellTftpHiiHandle, LocalFilePath, Status\r
516 );\r
517 }\r
518 ShellCloseFile (&FileHandle);\r
519\r
520 NextHandle:\r
521\r
522 if (Data != NULL) {\r
523 gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)Data, EFI_SIZE_TO_PAGES (FileSize));\r
524 }\r
525\r
526 CloseProtocolAndDestroyServiceChild (\r
527 ControllerHandle,\r
528 &gEfiMtftp4ServiceBindingProtocolGuid,\r
529 &gEfiMtftp4ProtocolGuid,\r
530 Mtftp4ChildHandle\r
531 );\r
532 }\r
533\r
a0f2af3a 534 if ((UserNicName != NULL) && (!NicFound)) {\r
68074260
RC
535 ShellPrintHiiEx (\r
536 -1, -1, NULL, STRING_TOKEN (STR_TFTP_ERR_NIC_NOT_FOUND),\r
537 gShellTftpHiiHandle, UserNicName\r
538 );\r
539 }\r
540\r
541 Error:\r
542\r
543 ShellCommandLineFreeVarList (CheckPackage);\r
544 if (AsciiRemoteFilePath != NULL) {\r
545 FreePool (AsciiRemoteFilePath);\r
546 }\r
547 if (Handles != NULL) {\r
548 FreePool (Handles);\r
549 }\r
550\r
551 return ShellStatus;\r
552}\r
553\r
554/**\r
555 Check and convert the UINT16 option values of the 'tftp' command\r
556\r
557 @param[in] ValueStr Value as an Unicode encoded string\r
558 @param[out] Value UINT16 value\r
559\r
560 @return TRUE The value was returned.\r
561 @return FALSE A parsing error occured.\r
562**/\r
563STATIC\r
564BOOLEAN\r
565StringToUint16 (\r
566 IN CONST CHAR16 *ValueStr,\r
567 OUT UINT16 *Value\r
568 )\r
569{\r
570 UINTN Val;\r
571\r
572 Val = ShellStrToUintn (ValueStr);\r
573 if (Val > MAX_UINT16) {\r
574 ShellPrintHiiEx (\r
575 -1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV),\r
576 gShellTftpHiiHandle, L"tftp", ValueStr\r
577 );\r
578 return FALSE;\r
579 }\r
580\r
6add86ab 581 *Value = (UINT16)Val;\r
68074260
RC
582 return TRUE;\r
583}\r
584\r
585/**\r
586 Get the name of the NIC.\r
587\r
588 @param[in] ControllerHandle The network physical device handle.\r
589 @param[in] NicNumber The network physical device number.\r
590 @param[out] NicName Address where to store the NIC name.\r
591 The memory area has to be at least\r
6add86ab
JC
592 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH \r
593 double byte wide.\r
68074260
RC
594\r
595 @return EFI_SUCCESS The name of the NIC was returned.\r
596 @return Others The creation of the child for the Managed\r
597 Network Service failed or the opening of\r
598 the Managed Network Protocol failed or\r
599 the operational parameters for the\r
600 Managed Network Protocol could not be\r
601 read.\r
602**/\r
603STATIC\r
604EFI_STATUS\r
605GetNicName (\r
606 IN EFI_HANDLE ControllerHandle,\r
607 IN UINTN NicNumber,\r
608 OUT CHAR16 *NicName\r
609 )\r
610{\r
611 EFI_STATUS Status;\r
612 EFI_HANDLE MnpHandle;\r
613 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;\r
614 EFI_SIMPLE_NETWORK_MODE SnpMode;\r
615\r
616 Status = CreateServiceChildAndOpenProtocol (\r
617 ControllerHandle,\r
618 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
619 &gEfiManagedNetworkProtocolGuid,\r
620 &MnpHandle,\r
621 (VOID**)&Mnp\r
622 );\r
623 if (EFI_ERROR (Status)) {\r
624 goto Error;\r
625 }\r
626\r
627 Status = Mnp->GetModeData (Mnp, NULL, &SnpMode);\r
628 if (EFI_ERROR (Status) && (Status != EFI_NOT_STARTED)) {\r
629 goto Error;\r
630 }\r
631\r
632 UnicodeSPrint (\r
633 NicName,\r
6add86ab 634 IP4_CONFIG2_INTERFACE_INFO_NAME_LENGTH,\r
68074260
RC
635 SnpMode.IfType == NET_IFTYPE_ETHERNET ?\r
636 L"eth%d" :\r
637 L"unk%d" ,\r
638 NicNumber\r
639 );\r
640\r
641 Status = EFI_SUCCESS;\r
642\r
643Error:\r
644\r
645 if (MnpHandle != NULL) {\r
646 CloseProtocolAndDestroyServiceChild (\r
647 ControllerHandle,\r
648 &gEfiManagedNetworkServiceBindingProtocolGuid,\r
649 &gEfiManagedNetworkProtocolGuid,\r
650 MnpHandle\r
651 );\r
652 }\r
653\r
654 return Status;\r
655}\r
656\r
657/**\r
658 Create a child for the service identified by its service binding protocol GUID\r
659 and get from the child the interface of the protocol identified by its GUID.\r
660\r
661 @param[in] ControllerHandle Controller handle.\r
662 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the\r
663 service to be created.\r
664 @param[in] ProtocolGuid GUID of the protocol to be open.\r
665 @param[out] ChildHandle Address where the handler of the\r
666 created child is returned. NULL is\r
667 returned in case of error.\r
668 @param[out] Interface Address where a pointer to the\r
669 protocol interface is returned in\r
670 case of success.\r
671\r
672 @return EFI_SUCCESS The child was created and the protocol opened.\r
673 @return Others Either the creation of the child or the opening\r
674 of the protocol failed.\r
675**/\r
676STATIC\r
677EFI_STATUS\r
678CreateServiceChildAndOpenProtocol (\r
679 IN EFI_HANDLE ControllerHandle,\r
680 IN EFI_GUID *ServiceBindingProtocolGuid,\r
681 IN EFI_GUID *ProtocolGuid,\r
682 OUT EFI_HANDLE *ChildHandle,\r
683 OUT VOID **Interface\r
684 )\r
685{\r
686 EFI_STATUS Status;\r
687\r
688 *ChildHandle = NULL;\r
689 Status = NetLibCreateServiceChild (\r
690 ControllerHandle,\r
691 gImageHandle,\r
692 ServiceBindingProtocolGuid,\r
693 ChildHandle\r
694 );\r
695 if (!EFI_ERROR (Status)) {\r
696 Status = gBS->OpenProtocol (\r
697 *ChildHandle,\r
698 ProtocolGuid,\r
699 Interface,\r
700 gImageHandle,\r
701 ControllerHandle,\r
702 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
703 );\r
704 if (EFI_ERROR (Status)) {\r
705 NetLibDestroyServiceChild (\r
706 ControllerHandle,\r
707 gImageHandle,\r
708 ServiceBindingProtocolGuid,\r
709 *ChildHandle\r
710 );\r
711 *ChildHandle = NULL;\r
712 }\r
713 }\r
714\r
715 return Status;\r
716}\r
717\r
718/**\r
719 Close the protocol identified by its GUID on the child handle of the service\r
720 identified by its service binding protocol GUID, then destroy the child\r
721 handle.\r
722\r
723 @param[in] ControllerHandle Controller handle.\r
724 @param[in] ServiceBindingProtocolGuid Service binding protocol GUID of the\r
725 service to be destroyed.\r
726 @param[in] ProtocolGuid GUID of the protocol to be closed.\r
727 @param[in] ChildHandle Handle of the child to be destroyed.\r
728\r
729**/\r
730STATIC\r
731VOID\r
732CloseProtocolAndDestroyServiceChild (\r
733 IN EFI_HANDLE ControllerHandle,\r
734 IN EFI_GUID *ServiceBindingProtocolGuid,\r
735 IN EFI_GUID *ProtocolGuid,\r
736 IN EFI_HANDLE ChildHandle\r
737 )\r
738{\r
739 gBS->CloseProtocol (\r
740 ChildHandle,\r
741 ProtocolGuid,\r
742 gImageHandle,\r
743 ControllerHandle\r
744 );\r
745\r
746 NetLibDestroyServiceChild (\r
747 ControllerHandle,\r
748 gImageHandle,\r
749 ServiceBindingProtocolGuid,\r
750 ChildHandle\r
751 );\r
752}\r
753\r
754/**\r
755 Worker function that gets the size in numbers of bytes of a file from a TFTP\r
756 server before to download the file.\r
757\r
758 @param[in] Mtftp4 MTFTP4 protocol interface\r
759 @param[in] FilePath Path of the file, ASCII encoded\r
760 @param[out] FileSize Address where to store the file size in number of\r
761 bytes.\r
762\r
763 @retval EFI_SUCCESS The size of the file was returned.\r
764 @retval EFI_UNSUPPORTED The server does not support the "tsize" option.\r
765 @retval Others Error when retrieving the information from the server\r
766 (see EFI_MTFTP4_PROTOCOL.GetInfo() status codes)\r
767 or error when parsing the response of the server.\r
768**/\r
769STATIC\r
770EFI_STATUS\r
771GetFileSize (\r
772 IN EFI_MTFTP4_PROTOCOL *Mtftp4,\r
773 IN CONST CHAR8 *FilePath,\r
774 OUT UINTN *FileSize\r
775 )\r
776{\r
777 EFI_STATUS Status;\r
778 EFI_MTFTP4_OPTION ReqOpt[1];\r
779 EFI_MTFTP4_PACKET *Packet;\r
780 UINT32 PktLen;\r
781 EFI_MTFTP4_OPTION *TableOfOptions;\r
782 EFI_MTFTP4_OPTION *Option;\r
783 UINT32 OptCnt;\r
784 UINT8 OptBuf[128];\r
785\r
786 ReqOpt[0].OptionStr = (UINT8*)"tsize";\r
787 OptBuf[0] = '0';\r
788 OptBuf[1] = 0;\r
789 ReqOpt[0].ValueStr = OptBuf;\r
790\r
791 Status = Mtftp4->GetInfo (\r
792 Mtftp4,\r
793 NULL,\r
794 (UINT8*)FilePath,\r
795 NULL,\r
796 1,\r
797 ReqOpt,\r
798 &PktLen,\r
799 &Packet\r
800 );\r
801\r
802 if (EFI_ERROR (Status)) {\r
803 goto Error;\r
804 }\r
805\r
806 Status = Mtftp4->ParseOptions (\r
807 Mtftp4,\r
808 PktLen,\r
809 Packet,\r
810 (UINT32 *) &OptCnt,\r
811 &TableOfOptions\r
812 );\r
813 if (EFI_ERROR (Status)) {\r
814 goto Error;\r
815 }\r
816\r
817 Option = TableOfOptions;\r
818 while (OptCnt != 0) {\r
819 if (AsciiStrnCmp ((CHAR8 *)Option->OptionStr, "tsize", 5) == 0) {\r
820 *FileSize = AsciiStrDecimalToUintn ((CHAR8 *)Option->ValueStr);\r
821 break;\r
822 }\r
823 OptCnt--;\r
824 Option++;\r
825 }\r
826 FreePool (TableOfOptions);\r
827\r
828 if (OptCnt == 0) {\r
829 Status = EFI_UNSUPPORTED;\r
830 }\r
831\r
832Error :\r
833\r
834 return Status;\r
835}\r
836\r
837/**\r
838 Worker function that download the data of a file from a TFTP server given\r
839 the path of the file and its size.\r
840\r
841 @param[in] Mtftp4 MTFTP4 protocol interface\r
842 @param[in] FilePath Path of the file, Unicode encoded\r
843 @param[in] AsciiFilePath Path of the file, ASCII encoded\r
844 @param[in] FileSize Size of the file in number of bytes\r
845 @param[out] Data Address where to store the address of the buffer\r
846 where the data of the file were downloaded in\r
847 case of success.\r
848\r
849 @retval EFI_SUCCESS The file was downloaded.\r
850 @retval EFI_OUT_OF_RESOURCES A memory allocation failed.\r
851 @retval Others The downloading of the file from the server failed\r
852 (see EFI_MTFTP4_PROTOCOL.ReadFile() status codes).\r
853\r
854**/\r
855STATIC\r
856EFI_STATUS\r
857DownloadFile (\r
858 IN EFI_MTFTP4_PROTOCOL *Mtftp4,\r
859 IN CONST CHAR16 *FilePath,\r
860 IN CONST CHAR8 *AsciiFilePath,\r
861 IN UINTN FileSize,\r
862 OUT VOID **Data\r
863 )\r
864{\r
865 EFI_STATUS Status;\r
866 EFI_PHYSICAL_ADDRESS PagesAddress;\r
867 VOID *Buffer;\r
868 DOWNLOAD_CONTEXT *TftpContext;\r
869 EFI_MTFTP4_TOKEN Mtftp4Token;\r
870\r
871 // Downloaded file can be large. BS.AllocatePages() is more faster\r
872 // than AllocatePool() and avoid fragmentation.\r
873 // The downloaded file could be an EFI application. Marking the\r
874 // allocated page as EfiBootServicesCode would allow to execute a\r
875 // potential downloaded EFI application.\r
876 Status = gBS->AllocatePages (\r
877 AllocateAnyPages,\r
878 EfiBootServicesCode,\r
879 EFI_SIZE_TO_PAGES (FileSize),\r
880 &PagesAddress\r
881 );\r
882 if (EFI_ERROR (Status)) {\r
883 return Status;\r
884 }\r
885\r
886 Buffer = (VOID*)(UINTN)PagesAddress;\r
887 TftpContext = AllocatePool (sizeof (DOWNLOAD_CONTEXT));\r
888 if (TftpContext == NULL) {\r
889 Status = EFI_OUT_OF_RESOURCES;\r
890 goto Error;\r
891 }\r
892 TftpContext->FileSize = FileSize;\r
893 TftpContext->DownloadedNbOfBytes = 0;\r
894 TftpContext->LastReportedNbOfBytes = 0;\r
895\r
896 ZeroMem (&Mtftp4Token, sizeof (EFI_MTFTP4_TOKEN));\r
897 Mtftp4Token.Filename = (UINT8*)AsciiFilePath;\r
898 Mtftp4Token.BufferSize = FileSize;\r
899 Mtftp4Token.Buffer = Buffer;\r
900 Mtftp4Token.CheckPacket = CheckPacket;\r
901 Mtftp4Token.Context = (VOID*)TftpContext;\r
902\r
903 ShellPrintHiiEx (\r
904 -1, -1, NULL, STRING_TOKEN (STR_TFTP_DOWNLOADING),\r
905 gShellTftpHiiHandle, FilePath\r
906 );\r
907\r
908 Status = Mtftp4->ReadFile (Mtftp4, &Mtftp4Token);\r
909 ShellPrintHiiEx (\r
910 -1, -1, NULL, STRING_TOKEN (STR_GEN_CRLF),\r
911 gShellTftpHiiHandle\r
912 );\r
913\r
914Error :\r
915\r
916 if (TftpContext == NULL) {\r
917 FreePool (TftpContext);\r
918 }\r
919\r
920 if (EFI_ERROR (Status)) {\r
921 gBS->FreePages (PagesAddress, EFI_SIZE_TO_PAGES (FileSize));\r
922 return Status;\r
923 }\r
924\r
925 *Data = Buffer;\r
926\r
927 return EFI_SUCCESS;\r
928}\r
929\r
930/**\r
931 Update the progress of a file download\r
932 This procedure is called each time a new TFTP packet is received.\r
933\r
934 @param[in] This MTFTP4 protocol interface\r
935 @param[in] Token Parameters for the download of the file\r
936 @param[in] PacketLen Length of the packet\r
937 @param[in] Packet Address of the packet\r
938\r
939 @retval EFI_SUCCESS All packets are accepted.\r
940\r
941**/\r
942STATIC\r
943EFI_STATUS\r
7367e66f 944EFIAPI\r
68074260
RC
945CheckPacket (\r
946 IN EFI_MTFTP4_PROTOCOL *This,\r
947 IN EFI_MTFTP4_TOKEN *Token,\r
948 IN UINT16 PacketLen,\r
949 IN EFI_MTFTP4_PACKET *Packet\r
950 )\r
951{\r
952 DOWNLOAD_CONTEXT *Context;\r
953 CHAR16 Progress[TFTP_PROGRESS_MESSAGE_SIZE];\r
6add86ab 954 UINTN NbOfKb;\r
68074260 955 UINTN Index;\r
310b053a
JC
956 UINTN LastStep;\r
957 UINTN Step;\r
68074260
RC
958\r
959 if ((NTOHS (Packet->OpCode)) != EFI_MTFTP4_OPCODE_DATA) {\r
960 return EFI_SUCCESS;\r
961 }\r
962\r
963 Context = (DOWNLOAD_CONTEXT*)Token->Context;\r
964 if (Context->DownloadedNbOfBytes == 0) {\r
965 ShellPrintEx (-1, -1, L"%s 0 Kb", mTftpProgressFrame);\r
966 }\r
967\r
968 //\r
969 // The data in the packet are prepended with two UINT16 :\r
970 // . OpCode = EFI_MTFTP4_OPCODE_DATA\r
971 // . Block = the number of this block of data\r
972 //\r
973 Context->DownloadedNbOfBytes += PacketLen - sizeof (Packet->OpCode)\r
974 - sizeof (Packet->Data.Block);\r
975 NbOfKb = Context->DownloadedNbOfBytes / 1024;\r
976\r
977 Progress[0] = L'\0';\r
6add86ab
JC
978 LastStep = (Context->LastReportedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;\r
979 Step = (Context->DownloadedNbOfBytes * TFTP_PROGRESS_SLIDER_STEPS) / Context->FileSize;\r
980\r
68074260
RC
981 if (Step <= LastStep) {\r
982 return EFI_SUCCESS;\r
983 }\r
984\r
985 ShellPrintEx (-1, -1, L"%s", mTftpProgressDelete);\r
986\r
987 StrCpy (Progress, mTftpProgressFrame);\r
988 for (Index = 1; Index < Step; Index++) {\r
989 Progress[Index] = L'=';\r
990 }\r
991 Progress[Step] = L'>';\r
992\r
993 UnicodeSPrint (\r
994 Progress + (sizeof (mTftpProgressFrame) / sizeof (CHAR16)) - 1,\r
995 sizeof (Progress) - sizeof (mTftpProgressFrame),\r
996 L" %7d Kb",\r
997 NbOfKb\r
998 );\r
999 Context->LastReportedNbOfBytes = Context->DownloadedNbOfBytes;\r
1000\r
1001 ShellPrintEx (-1, -1, L"%s", Progress);\r
1002\r
1003 return EFI_SUCCESS;\r
1004}\r