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