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