Tftp.c 35 KB

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