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