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