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