PxeBcBoot.c 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  1. /** @file
  2. Boot functions implementation for UefiPxeBc Driver.
  3. Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
  4. (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "PxeBcImpl.h"
  8. /**
  9. Display the string of the boot item.
  10. If the length of the boot item string beyond 70 Char, just display 70 Char.
  11. @param[in] Str The pointer to the string.
  12. @param[in] Len The length of the string.
  13. **/
  14. VOID
  15. PxeBcDisplayBootItem (
  16. IN UINT8 *Str,
  17. IN UINT8 Len
  18. )
  19. {
  20. UINT8 Tmp;
  21. //
  22. // Cut off the chars behind 70th.
  23. //
  24. Len = (UINT8)MIN (PXEBC_DISPLAY_MAX_LINE, Len);
  25. Tmp = Str[Len];
  26. Str[Len] = 0;
  27. AsciiPrint ("%a \n", Str);
  28. //
  29. // Restore the original 70th char.
  30. //
  31. Str[Len] = Tmp;
  32. }
  33. /**
  34. Select and maintain the boot prompt if needed.
  35. @param[in] Private Pointer to PxeBc private data.
  36. @retval EFI_SUCCESS Selected boot prompt done.
  37. @retval EFI_TIMEOUT Selected boot prompt timed out.
  38. @retval EFI_NOT_FOUND The proxy offer is not Pxe10.
  39. @retval EFI_ABORTED User cancelled the operation.
  40. @retval EFI_NOT_READY Reading the input key from the keyboard has not finish.
  41. **/
  42. EFI_STATUS
  43. PxeBcSelectBootPrompt (
  44. IN PXEBC_PRIVATE_DATA *Private
  45. )
  46. {
  47. PXEBC_DHCP_PACKET_CACHE *Cache;
  48. PXEBC_VENDOR_OPTION *VendorOpt;
  49. EFI_PXE_BASE_CODE_MODE *Mode;
  50. EFI_EVENT TimeoutEvent;
  51. EFI_EVENT DescendEvent;
  52. EFI_INPUT_KEY InputKey;
  53. EFI_STATUS Status;
  54. UINT32 OfferType;
  55. UINT8 Timeout;
  56. UINT8 *Prompt;
  57. UINT8 PromptLen;
  58. INT32 SecCol;
  59. INT32 SecRow;
  60. TimeoutEvent = NULL;
  61. DescendEvent = NULL;
  62. Mode = Private->PxeBc.Mode;
  63. Cache = Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Private->DhcpAck;
  64. OfferType = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;
  65. //
  66. // Only DhcpPxe10 and ProxyPxe10 offer needs boot prompt.
  67. //
  68. if ((OfferType != PxeOfferTypeProxyPxe10) && (OfferType != PxeOfferTypeDhcpPxe10)) {
  69. return EFI_NOT_FOUND;
  70. }
  71. //
  72. // There is no specified ProxyPxe10 for IPv6 in PXE and UEFI spec.
  73. //
  74. ASSERT (!Mode->UsingIpv6);
  75. VendorOpt = &Cache->Dhcp4.VendorOpt;
  76. //
  77. // According to the PXE specification 2.1, Table 2-1 PXE DHCP Options,
  78. // we must not consider a boot prompt or boot menu if all of the following hold:
  79. // - the PXE_DISCOVERY_CONTROL tag(6) is present inside the Vendor Options(43), and has bit 3 set
  80. // - a boot file name has been presented in the initial DHCP or ProxyDHCP offer packet.
  81. //
  82. if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) &&
  83. (Cache->Dhcp4.OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL))
  84. {
  85. return EFI_ABORTED;
  86. }
  87. if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {
  88. return EFI_TIMEOUT;
  89. }
  90. Timeout = VendorOpt->MenuPrompt->Timeout;
  91. Prompt = VendorOpt->MenuPrompt->Prompt;
  92. PromptLen = (UINT8)(VendorOpt->MenuPromptLen - 1);
  93. //
  94. // The valid scope of Timeout refers to PXE2.1 spec.
  95. //
  96. if (Timeout == 0) {
  97. return EFI_TIMEOUT;
  98. }
  99. if (Timeout == 255) {
  100. return EFI_SUCCESS;
  101. }
  102. //
  103. // Create and start a timer as timeout event.
  104. //
  105. Status = gBS->CreateEvent (
  106. EVT_TIMER,
  107. TPL_CALLBACK,
  108. NULL,
  109. NULL,
  110. &TimeoutEvent
  111. );
  112. if (EFI_ERROR (Status)) {
  113. return Status;
  114. }
  115. Status = gBS->SetTimer (
  116. TimeoutEvent,
  117. TimerRelative,
  118. MultU64x32 (Timeout, TICKS_PER_SECOND)
  119. );
  120. if (EFI_ERROR (Status)) {
  121. goto ON_EXIT;
  122. }
  123. //
  124. // Create and start a periodic timer as descend event by second.
  125. //
  126. Status = gBS->CreateEvent (
  127. EVT_TIMER,
  128. TPL_CALLBACK,
  129. NULL,
  130. NULL,
  131. &DescendEvent
  132. );
  133. if (EFI_ERROR (Status)) {
  134. goto ON_EXIT;
  135. }
  136. Status = gBS->SetTimer (
  137. DescendEvent,
  138. TimerPeriodic,
  139. TICKS_PER_SECOND
  140. );
  141. if (EFI_ERROR (Status)) {
  142. goto ON_EXIT;
  143. }
  144. //
  145. // Display the boot item and cursor on the screen.
  146. //
  147. SecCol = gST->ConOut->Mode->CursorColumn;
  148. SecRow = gST->ConOut->Mode->CursorRow;
  149. PxeBcDisplayBootItem (Prompt, PromptLen);
  150. gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);
  151. AsciiPrint ("(%d) ", Timeout--);
  152. Status = EFI_TIMEOUT;
  153. while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
  154. if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {
  155. gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);
  156. AsciiPrint ("(%d) ", Timeout--);
  157. }
  158. if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {
  159. gBS->Stall (10 * TICKS_PER_MS);
  160. continue;
  161. }
  162. //
  163. // Parse the input key by user.
  164. // If <F8> or <Ctrl> + <M> is pressed, return success to display the boot menu.
  165. //
  166. if (InputKey.ScanCode == 0) {
  167. switch (InputKey.UnicodeChar) {
  168. case CTRL ('c'):
  169. Status = EFI_ABORTED;
  170. break;
  171. case CTRL ('m'):
  172. case 'm':
  173. case 'M':
  174. Status = EFI_SUCCESS;
  175. break;
  176. default:
  177. continue;
  178. }
  179. } else {
  180. switch (InputKey.ScanCode) {
  181. case SCAN_F8:
  182. Status = EFI_SUCCESS;
  183. break;
  184. case SCAN_ESC:
  185. Status = EFI_ABORTED;
  186. break;
  187. default:
  188. continue;
  189. }
  190. }
  191. break;
  192. }
  193. //
  194. // Reset the cursor on the screen.
  195. //
  196. gST->ConOut->SetCursorPosition (gST->ConOut, 0, SecRow + 1);
  197. ON_EXIT:
  198. if (DescendEvent != NULL) {
  199. gBS->CloseEvent (DescendEvent);
  200. }
  201. if (TimeoutEvent != NULL) {
  202. gBS->CloseEvent (TimeoutEvent);
  203. }
  204. return Status;
  205. }
  206. /**
  207. Select the boot menu by user's input.
  208. @param[in] Private Pointer to PxeBc private data.
  209. @param[out] Type The type of the menu.
  210. @param[in] UseDefaultItem Use default item or not.
  211. @retval EFI_ABORTED User cancel operation.
  212. @retval EFI_SUCCESS Select the boot menu success.
  213. @retval EFI_NOT_READY Read the input key from the keyboard has not finish.
  214. **/
  215. EFI_STATUS
  216. PxeBcSelectBootMenu (
  217. IN PXEBC_PRIVATE_DATA *Private,
  218. OUT UINT16 *Type,
  219. IN BOOLEAN UseDefaultItem
  220. )
  221. {
  222. EFI_PXE_BASE_CODE_MODE *Mode;
  223. PXEBC_DHCP_PACKET_CACHE *Cache;
  224. PXEBC_VENDOR_OPTION *VendorOpt;
  225. EFI_INPUT_KEY InputKey;
  226. UINT32 OfferType;
  227. UINT8 MenuSize;
  228. UINT8 MenuNum;
  229. INT32 TopRow;
  230. UINT16 Select;
  231. UINT16 LastSelect;
  232. UINT8 Index;
  233. BOOLEAN Finish;
  234. CHAR8 Blank[PXEBC_DISPLAY_MAX_LINE];
  235. PXEBC_BOOT_MENU_ENTRY *MenuItem;
  236. PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MENU_MAX_NUM];
  237. Finish = FALSE;
  238. Select = 0;
  239. Index = 0;
  240. *Type = 0;
  241. Mode = Private->PxeBc.Mode;
  242. Cache = Mode->ProxyOfferReceived ? &Private->ProxyOffer : &Private->DhcpAck;
  243. OfferType = Mode->UsingIpv6 ? Cache->Dhcp6.OfferType : Cache->Dhcp4.OfferType;
  244. //
  245. // There is no specified DhcpPxe10/ProxyPxe10 for IPv6 in PXE and UEFI spec.
  246. //
  247. ASSERT (!Mode->UsingIpv6);
  248. ASSERT (OfferType == PxeOfferTypeProxyPxe10 || OfferType == PxeOfferTypeDhcpPxe10);
  249. VendorOpt = &Cache->Dhcp4.VendorOpt;
  250. if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {
  251. return EFI_SUCCESS;
  252. }
  253. //
  254. // Display the boot menu on the screen.
  255. //
  256. SetMem (Blank, sizeof (Blank), ' ');
  257. MenuSize = VendorOpt->BootMenuLen;
  258. MenuItem = VendorOpt->BootMenu;
  259. if (MenuSize == 0) {
  260. return EFI_DEVICE_ERROR;
  261. }
  262. while (MenuSize > 0 && Index < PXEBC_MENU_MAX_NUM) {
  263. ASSERT (MenuItem != NULL);
  264. MenuArray[Index] = MenuItem;
  265. MenuSize = (UINT8)(MenuSize - (MenuItem->DescLen + 3));
  266. MenuItem = (PXEBC_BOOT_MENU_ENTRY *)((UINT8 *)MenuItem + MenuItem->DescLen + 3);
  267. Index++;
  268. }
  269. if (UseDefaultItem) {
  270. ASSERT (MenuArray[0] != NULL);
  271. CopyMem (Type, &MenuArray[0]->Type, sizeof (UINT16));
  272. *Type = NTOHS (*Type);
  273. return EFI_SUCCESS;
  274. }
  275. MenuNum = Index;
  276. for (Index = 0; Index < MenuNum; Index++) {
  277. ASSERT (MenuArray[Index] != NULL);
  278. PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);
  279. }
  280. TopRow = gST->ConOut->Mode->CursorRow - MenuNum;
  281. //
  282. // Select the boot item by user in the boot menu.
  283. //
  284. do {
  285. //
  286. // Highlight selected row.
  287. //
  288. gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));
  289. gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);
  290. ASSERT (Select < PXEBC_MENU_MAX_NUM);
  291. ASSERT (MenuArray[Select] != NULL);
  292. Blank[MenuArray[Select]->DescLen] = 0;
  293. AsciiPrint ("%a\r", Blank);
  294. PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);
  295. gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);
  296. LastSelect = Select;
  297. while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {
  298. gBS->Stall (10 * TICKS_PER_MS);
  299. }
  300. if (InputKey.ScanCode == 0) {
  301. switch (InputKey.UnicodeChar) {
  302. case CTRL ('c'):
  303. InputKey.ScanCode = SCAN_ESC;
  304. break;
  305. case CTRL ('j'): /* linefeed */
  306. case CTRL ('m'): /* return */
  307. Finish = TRUE;
  308. break;
  309. case CTRL ('i'): /* tab */
  310. case ' ':
  311. case 'd':
  312. case 'D':
  313. InputKey.ScanCode = SCAN_DOWN;
  314. break;
  315. case CTRL ('h'): /* backspace */
  316. case 'u':
  317. case 'U':
  318. InputKey.ScanCode = SCAN_UP;
  319. break;
  320. default:
  321. InputKey.ScanCode = 0;
  322. }
  323. }
  324. switch (InputKey.ScanCode) {
  325. case SCAN_LEFT:
  326. case SCAN_UP:
  327. if (Select != 0) {
  328. Select--;
  329. }
  330. break;
  331. case SCAN_DOWN:
  332. case SCAN_RIGHT:
  333. if (++Select == MenuNum) {
  334. Select--;
  335. }
  336. break;
  337. case SCAN_PAGE_UP:
  338. case SCAN_HOME:
  339. Select = 0;
  340. break;
  341. case SCAN_PAGE_DOWN:
  342. case SCAN_END:
  343. Select = (UINT16)(MenuNum - 1);
  344. break;
  345. case SCAN_ESC:
  346. return EFI_ABORTED;
  347. }
  348. //
  349. // Unhighlight the last selected row.
  350. //
  351. gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));
  352. gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);
  353. ASSERT (LastSelect < PXEBC_MENU_MAX_NUM);
  354. ASSERT (MenuArray[LastSelect] != NULL);
  355. Blank[MenuArray[LastSelect]->DescLen] = 0;
  356. AsciiPrint ("%a\r", Blank);
  357. PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);
  358. gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);
  359. } while (!Finish);
  360. //
  361. // Swap the byte order.
  362. //
  363. ASSERT (Select < PXEBC_MENU_MAX_NUM);
  364. ASSERT (MenuArray[Select] != NULL);
  365. CopyMem (Type, &MenuArray[Select]->Type, sizeof (UINT16));
  366. *Type = NTOHS (*Type);
  367. return EFI_SUCCESS;
  368. }
  369. /**
  370. Parse out the boot information from the last Dhcp4 reply packet.
  371. @param[in, out] Private Pointer to PxeBc private data.
  372. @param[out] BufferSize Size of the boot file to be downloaded.
  373. @retval EFI_SUCCESS Successfully parsed out all the boot information.
  374. @retval Others Failed to parse out the boot information.
  375. **/
  376. EFI_STATUS
  377. PxeBcDhcp4BootInfo (
  378. IN OUT PXEBC_PRIVATE_DATA *Private,
  379. OUT UINT64 *BufferSize
  380. )
  381. {
  382. EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
  383. EFI_PXE_BASE_CODE_MODE *Mode;
  384. EFI_STATUS Status;
  385. PXEBC_DHCP4_PACKET_CACHE *Cache4;
  386. UINT16 Value;
  387. PXEBC_VENDOR_OPTION *VendorOpt;
  388. PXEBC_BOOT_SVR_ENTRY *Entry;
  389. PxeBc = &Private->PxeBc;
  390. Mode = PxeBc->Mode;
  391. Status = EFI_SUCCESS;
  392. *BufferSize = 0;
  393. //
  394. // Get the last received Dhcp4 reply packet.
  395. //
  396. if (Mode->PxeReplyReceived) {
  397. Cache4 = &Private->PxeReply.Dhcp4;
  398. } else if (Mode->ProxyOfferReceived) {
  399. Cache4 = &Private->ProxyOffer.Dhcp4;
  400. } else {
  401. Cache4 = &Private->DhcpAck.Dhcp4;
  402. }
  403. if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) {
  404. //
  405. // This should never happen in a correctly configured DHCP / PXE
  406. // environment. One misconfiguration that can cause it is two DHCP servers
  407. // mistakenly running on the same network segment at the same time, and
  408. // racing each other in answering DHCP requests. Thus, the DHCP packets
  409. // that the edk2 PXE client considers "belonging together" may actually be
  410. // entirely independent, coming from two (competing) DHCP servers.
  411. //
  412. // Try to deal with this gracefully. Note that this check is not
  413. // comprehensive, as we don't try to identify all such errors.
  414. //
  415. return EFI_PROTOCOL_ERROR;
  416. }
  417. //
  418. // Parse the boot server address.
  419. // If prompt/discover is disabled, get the first boot server from the boot servers list.
  420. // Otherwise, parse the boot server Ipv4 address from next server address field in DHCP header.
  421. // If all these fields are not available, use option 54 instead.
  422. //
  423. VendorOpt = &Cache4->VendorOpt;
  424. if (IS_DISABLE_PROMPT_MENU (VendorOpt->DiscoverCtrl) && IS_VALID_BOOT_SERVERS (VendorOpt->BitMap)) {
  425. Entry = VendorOpt->BootSvr;
  426. if ((VendorOpt->BootSvrLen >= sizeof (PXEBC_BOOT_SVR_ENTRY)) && (Entry->IpCnt > 0)) {
  427. CopyMem (
  428. &Private->ServerIp,
  429. &Entry->IpAddr[0],
  430. sizeof (EFI_IPv4_ADDRESS)
  431. );
  432. }
  433. }
  434. if (Private->ServerIp.Addr[0] == 0) {
  435. //
  436. // ServerIp.Addr[0] equals zero means we failed to get IP address from boot server list.
  437. // Try to use next server address field.
  438. //
  439. CopyMem (
  440. &Private->ServerIp,
  441. &Cache4->Packet.Offer.Dhcp4.Header.ServerAddr,
  442. sizeof (EFI_IPv4_ADDRESS)
  443. );
  444. }
  445. if (Private->ServerIp.Addr[0] == 0) {
  446. //
  447. // Still failed , use the IP address from option 54.
  448. //
  449. CopyMem (
  450. &Private->ServerIp,
  451. Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,
  452. sizeof (EFI_IPv4_ADDRESS)
  453. );
  454. }
  455. //
  456. // Parse the boot file name by option.
  457. //
  458. Private->BootFileName = Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE]->Data;
  459. if (Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN] != NULL) {
  460. //
  461. // Parse the boot file size by option.
  462. //
  463. CopyMem (&Value, Cache4->OptList[PXEBC_DHCP4_TAG_INDEX_BOOTFILE_LEN]->Data, sizeof (Value));
  464. Value = NTOHS (Value);
  465. //
  466. // The field of boot file size is 512 bytes in unit.
  467. //
  468. *BufferSize = 512 * Value;
  469. } else {
  470. //
  471. // Get the bootfile size by tftp command if no option available.
  472. //
  473. Status = PxeBc->Mtftp (
  474. PxeBc,
  475. EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
  476. NULL,
  477. FALSE,
  478. BufferSize,
  479. &Private->BlockSize,
  480. &Private->ServerIp,
  481. Private->BootFileName,
  482. NULL,
  483. FALSE
  484. );
  485. }
  486. //
  487. // Save the value of boot file size.
  488. //
  489. Private->BootFileSize = (UINTN)*BufferSize;
  490. //
  491. // Display all the information: boot server address, boot file name and boot file size.
  492. //
  493. AsciiPrint ("\n Server IP address is ");
  494. PxeBcShowIp4Addr (&Private->ServerIp.v4);
  495. AsciiPrint ("\n NBP filename is %a", Private->BootFileName);
  496. AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize);
  497. return Status;
  498. }
  499. /**
  500. Parse out the boot information from the last Dhcp6 reply packet.
  501. @param[in, out] Private Pointer to PxeBc private data.
  502. @param[out] BufferSize Size of the boot file to be downloaded.
  503. @retval EFI_SUCCESS Successfully parsed out all the boot information.
  504. @retval EFI_BUFFER_TOO_SMALL
  505. @retval Others Failed to parse out the boot information.
  506. **/
  507. EFI_STATUS
  508. PxeBcDhcp6BootInfo (
  509. IN OUT PXEBC_PRIVATE_DATA *Private,
  510. OUT UINT64 *BufferSize
  511. )
  512. {
  513. EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
  514. EFI_PXE_BASE_CODE_MODE *Mode;
  515. EFI_STATUS Status;
  516. PXEBC_DHCP6_PACKET_CACHE *Cache6;
  517. UINT16 Value;
  518. PxeBc = &Private->PxeBc;
  519. Mode = PxeBc->Mode;
  520. Status = EFI_SUCCESS;
  521. *BufferSize = 0;
  522. //
  523. // Get the last received Dhcp6 reply packet.
  524. //
  525. if (Mode->PxeReplyReceived) {
  526. Cache6 = &Private->PxeReply.Dhcp6;
  527. } else if (Mode->ProxyOfferReceived) {
  528. Cache6 = &Private->ProxyOffer.Dhcp6;
  529. } else {
  530. Cache6 = &Private->DhcpAck.Dhcp6;
  531. }
  532. if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
  533. //
  534. // This should never happen in a correctly configured DHCP / PXE
  535. // environment. One misconfiguration that can cause it is two DHCP servers
  536. // mistakenly running on the same network segment at the same time, and
  537. // racing each other in answering DHCP requests. Thus, the DHCP packets
  538. // that the edk2 PXE client considers "belonging together" may actually be
  539. // entirely independent, coming from two (competing) DHCP servers.
  540. //
  541. // Try to deal with this gracefully. Note that this check is not
  542. // comprehensive, as we don't try to identify all such errors.
  543. //
  544. return EFI_PROTOCOL_ERROR;
  545. }
  546. //
  547. // Set the station address to IP layer.
  548. //
  549. Status = PxeBcSetIp6Address (Private);
  550. if (EFI_ERROR (Status)) {
  551. return Status;
  552. }
  553. //
  554. // Parse (m)tftp server ip address and bootfile name.
  555. //
  556. Status = PxeBcExtractBootFileUrl (
  557. Private,
  558. &Private->BootFileName,
  559. &Private->ServerIp.v6,
  560. (CHAR8 *)(Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
  561. NTOHS (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
  562. );
  563. if (EFI_ERROR (Status)) {
  564. return Status;
  565. }
  566. //
  567. // Parse the value of boot file size.
  568. //
  569. if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] != NULL) {
  570. //
  571. // Parse it out if have the boot file parameter option.
  572. //
  573. Status = PxeBcExtractBootFileParam ((CHAR8 *)Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM]->Data, &Value);
  574. if (EFI_ERROR (Status)) {
  575. return Status;
  576. }
  577. //
  578. // The field of boot file size is 512 bytes in unit.
  579. //
  580. *BufferSize = 512 * Value;
  581. } else {
  582. //
  583. // Send get file size command by tftp if option unavailable.
  584. //
  585. Status = PxeBc->Mtftp (
  586. PxeBc,
  587. EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
  588. NULL,
  589. FALSE,
  590. BufferSize,
  591. &Private->BlockSize,
  592. &Private->ServerIp,
  593. Private->BootFileName,
  594. NULL,
  595. FALSE
  596. );
  597. }
  598. //
  599. // Save the value of boot file size.
  600. //
  601. Private->BootFileSize = (UINTN)*BufferSize;
  602. //
  603. // Display all the information: boot server address, boot file name and boot file size.
  604. //
  605. AsciiPrint ("\n Server IP address is ");
  606. PxeBcShowIp6Addr (&Private->ServerIp.v6);
  607. AsciiPrint ("\n NBP filename is %a", Private->BootFileName);
  608. AsciiPrint ("\n NBP filesize is %d Bytes", Private->BootFileSize);
  609. return Status;
  610. }
  611. /**
  612. Extract the discover information and boot server entry from the
  613. cached packets if unspecified.
  614. @param[in] Private Pointer to PxeBc private data.
  615. @param[in] Type The type of bootstrap to perform.
  616. @param[in, out] DiscoverInfo Pointer to EFI_PXE_BASE_CODE_DISCOVER_INFO.
  617. @param[out] BootEntry Pointer to PXEBC_BOOT_SVR_ENTRY.
  618. @param[out] SrvList Pointer to EFI_PXE_BASE_CODE_SRVLIST.
  619. @retval EFI_SUCCESS Successfully extracted the information.
  620. @retval EFI_DEVICE_ERROR Failed to extract the information.
  621. **/
  622. EFI_STATUS
  623. PxeBcExtractDiscoverInfo (
  624. IN PXEBC_PRIVATE_DATA *Private,
  625. IN UINT16 Type,
  626. IN OUT EFI_PXE_BASE_CODE_DISCOVER_INFO **DiscoverInfo,
  627. OUT PXEBC_BOOT_SVR_ENTRY **BootEntry,
  628. OUT EFI_PXE_BASE_CODE_SRVLIST **SrvList
  629. )
  630. {
  631. EFI_PXE_BASE_CODE_MODE *Mode;
  632. PXEBC_DHCP4_PACKET_CACHE *Cache4;
  633. PXEBC_VENDOR_OPTION *VendorOpt;
  634. PXEBC_BOOT_SVR_ENTRY *Entry;
  635. BOOLEAN IsFound;
  636. EFI_PXE_BASE_CODE_DISCOVER_INFO *Info;
  637. UINT16 Index;
  638. Mode = Private->PxeBc.Mode;
  639. Info = *DiscoverInfo;
  640. if (Mode->UsingIpv6) {
  641. Info->IpCnt = 1;
  642. Info->UseUCast = TRUE;
  643. Info->SrvList[0].Type = Type;
  644. Info->SrvList[0].AcceptAnyResponse = FALSE;
  645. //
  646. // There is no vendor options specified in DHCPv6, so take BootFileUrl in the last cached packet.
  647. //
  648. CopyMem (&Info->SrvList[0].IpAddr, &Private->ServerIp, sizeof (EFI_IP_ADDRESS));
  649. *SrvList = Info->SrvList;
  650. } else {
  651. Entry = NULL;
  652. IsFound = FALSE;
  653. Cache4 = (Mode->ProxyOfferReceived) ? &Private->ProxyOffer.Dhcp4 : &Private->DhcpAck.Dhcp4;
  654. VendorOpt = &Cache4->VendorOpt;
  655. if (!Mode->DhcpAckReceived || !IS_VALID_DISCOVER_VENDOR_OPTION (VendorOpt->BitMap)) {
  656. //
  657. // Address is not acquired or no discovery options.
  658. //
  659. return EFI_INVALID_PARAMETER;
  660. }
  661. //
  662. // Parse the boot server entry from the vendor option in the last cached packet.
  663. //
  664. Info->UseMCast = (BOOLEAN) !IS_DISABLE_MCAST_DISCOVER (VendorOpt->DiscoverCtrl);
  665. Info->UseBCast = (BOOLEAN) !IS_DISABLE_BCAST_DISCOVER (VendorOpt->DiscoverCtrl);
  666. Info->MustUseList = (BOOLEAN)IS_ENABLE_USE_SERVER_LIST (VendorOpt->DiscoverCtrl);
  667. Info->UseUCast = (BOOLEAN)IS_VALID_BOOT_SERVERS (VendorOpt->BitMap);
  668. if (Info->UseMCast) {
  669. //
  670. // Get the multicast discover ip address from vendor option if has.
  671. //
  672. CopyMem (&Info->ServerMCastIp.v4, &VendorOpt->DiscoverMcastIp, sizeof (EFI_IPv4_ADDRESS));
  673. }
  674. Info->IpCnt = 0;
  675. if (Info->UseUCast) {
  676. Entry = VendorOpt->BootSvr;
  677. while (((UINT8)(Entry - VendorOpt->BootSvr)) < VendorOpt->BootSvrLen) {
  678. if (Entry->Type == HTONS (Type)) {
  679. IsFound = TRUE;
  680. break;
  681. }
  682. Entry = GET_NEXT_BOOT_SVR_ENTRY (Entry);
  683. }
  684. if (!IsFound) {
  685. return EFI_DEVICE_ERROR;
  686. }
  687. Info->IpCnt = Entry->IpCnt;
  688. if (Info->IpCnt >= 1) {
  689. *DiscoverInfo = AllocatePool (sizeof (*Info) + (Info->IpCnt - 1) * sizeof (**SrvList));
  690. if (*DiscoverInfo == NULL) {
  691. return EFI_OUT_OF_RESOURCES;
  692. }
  693. CopyMem (*DiscoverInfo, Info, sizeof (*Info));
  694. Info = *DiscoverInfo;
  695. }
  696. for (Index = 0; Index < Info->IpCnt; Index++) {
  697. CopyMem (&Info->SrvList[Index].IpAddr, &Entry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS));
  698. Info->SrvList[Index].AcceptAnyResponse = !Info->MustUseList;
  699. Info->SrvList[Index].Type = NTOHS (Entry->Type);
  700. }
  701. }
  702. *BootEntry = Entry;
  703. *SrvList = Info->SrvList;
  704. }
  705. return EFI_SUCCESS;
  706. }
  707. /**
  708. Build the discover packet and send out for boot server.
  709. @param[in] Private Pointer to PxeBc private data.
  710. @param[in] Type PxeBc option boot item type.
  711. @param[in] Layer Pointer to option boot item layer.
  712. @param[in] UseBis Use BIS or not.
  713. @param[in] DestIp Pointer to the destination address.
  714. @param[in] IpCount The count of the server address.
  715. @param[in] SrvList Pointer to the server address list.
  716. @retval EFI_SUCCESS Successfully discovered boot file.
  717. @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.
  718. @retval EFI_NOT_FOUND Can't get the PXE reply packet.
  719. @retval Others Failed to discover boot file.
  720. **/
  721. EFI_STATUS
  722. PxeBcDiscoverBootServer (
  723. IN PXEBC_PRIVATE_DATA *Private,
  724. IN UINT16 Type,
  725. IN UINT16 *Layer,
  726. IN BOOLEAN UseBis,
  727. IN EFI_IP_ADDRESS *DestIp,
  728. IN UINT16 IpCount,
  729. IN EFI_PXE_BASE_CODE_SRVLIST *SrvList
  730. )
  731. {
  732. if (Private->PxeBc.Mode->UsingIpv6) {
  733. return PxeBcDhcp6Discover (
  734. Private,
  735. Type,
  736. Layer,
  737. UseBis,
  738. DestIp
  739. );
  740. } else {
  741. return PxeBcDhcp4Discover (
  742. Private,
  743. Type,
  744. Layer,
  745. UseBis,
  746. DestIp,
  747. IpCount,
  748. SrvList
  749. );
  750. }
  751. }
  752. /**
  753. Discover all the boot information for boot file.
  754. @param[in, out] Private Pointer to PxeBc private data.
  755. @param[out] BufferSize Size of the boot file to be downloaded.
  756. @retval EFI_SUCCESS Successfully obtained all the boot information .
  757. @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
  758. @retval EFI_ABORTED User cancel current operation.
  759. @retval Others Failed to parse out the boot information.
  760. **/
  761. EFI_STATUS
  762. PxeBcDiscoverBootFile (
  763. IN OUT PXEBC_PRIVATE_DATA *Private,
  764. OUT UINT64 *BufferSize
  765. )
  766. {
  767. EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
  768. EFI_PXE_BASE_CODE_MODE *Mode;
  769. EFI_STATUS Status;
  770. UINT16 Type;
  771. UINT16 Layer;
  772. BOOLEAN UseBis;
  773. PxeBc = &Private->PxeBc;
  774. Mode = PxeBc->Mode;
  775. Type = EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP;
  776. Layer = EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL;
  777. //
  778. // Start D.O.R.A/S.A.R.R exchange to acquire station ip address and
  779. // other pxe boot information.
  780. //
  781. Status = PxeBc->Dhcp (PxeBc, TRUE);
  782. if (EFI_ERROR (Status)) {
  783. return Status;
  784. }
  785. //
  786. // Select a boot server from boot server list.
  787. //
  788. Status = PxeBcSelectBootPrompt (Private);
  789. if (Status == EFI_SUCCESS) {
  790. //
  791. // Choose by user's input.
  792. //
  793. Status = PxeBcSelectBootMenu (Private, &Type, FALSE);
  794. } else if (Status == EFI_TIMEOUT) {
  795. //
  796. // Choose by default item.
  797. //
  798. Status = PxeBcSelectBootMenu (Private, &Type, TRUE);
  799. }
  800. if (!EFI_ERROR (Status)) {
  801. if (Type == EFI_PXE_BASE_CODE_BOOT_TYPE_BOOTSTRAP) {
  802. //
  803. // Local boot(PXE bootstrap server) need abort
  804. //
  805. return EFI_ABORTED;
  806. }
  807. //
  808. // Start to discover the boot server to get (m)tftp server ip address, bootfile
  809. // name and bootfile size.
  810. //
  811. UseBis = (BOOLEAN)(Mode->BisSupported && Mode->BisDetected);
  812. Status = PxeBc->Discover (PxeBc, Type, &Layer, UseBis, NULL);
  813. if (EFI_ERROR (Status)) {
  814. return Status;
  815. }
  816. if (Mode->PxeReplyReceived && !Mode->ProxyOfferReceived) {
  817. //
  818. // Some network boot loader only search the packet in Mode.ProxyOffer to get its server
  819. // IP address, so we need to store a copy of Mode.PxeReply packet into Mode.ProxyOffer.
  820. //
  821. if (Mode->UsingIpv6) {
  822. CopyMem (
  823. &Mode->ProxyOffer.Dhcpv6,
  824. &Mode->PxeReply.Dhcpv6,
  825. Private->PxeReply.Dhcp6.Packet.Ack.Length
  826. );
  827. } else {
  828. CopyMem (
  829. &Mode->ProxyOffer.Dhcpv4,
  830. &Mode->PxeReply.Dhcpv4,
  831. Private->PxeReply.Dhcp4.Packet.Ack.Length
  832. );
  833. }
  834. Mode->ProxyOfferReceived = TRUE;
  835. }
  836. }
  837. //
  838. // Parse the boot information.
  839. //
  840. if (Mode->UsingIpv6) {
  841. Status = PxeBcDhcp6BootInfo (Private, BufferSize);
  842. } else {
  843. Status = PxeBcDhcp4BootInfo (Private, BufferSize);
  844. }
  845. return Status;
  846. }
  847. /**
  848. Install PxeBaseCodeCallbackProtocol if not installed before.
  849. @param[in, out] Private Pointer to PxeBc private data.
  850. @param[out] NewMakeCallback If TRUE, it is a new callback.
  851. Otherwise, it is not new callback.
  852. @retval EFI_SUCCESS PxeBaseCodeCallbackProtocol installed successfully.
  853. @retval Others Failed to install PxeBaseCodeCallbackProtocol.
  854. **/
  855. EFI_STATUS
  856. PxeBcInstallCallback (
  857. IN OUT PXEBC_PRIVATE_DATA *Private,
  858. OUT BOOLEAN *NewMakeCallback
  859. )
  860. {
  861. EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
  862. EFI_STATUS Status;
  863. //
  864. // Check whether PxeBaseCodeCallbackProtocol already installed.
  865. //
  866. PxeBc = &Private->PxeBc;
  867. Status = gBS->HandleProtocol (
  868. Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,
  869. &gEfiPxeBaseCodeCallbackProtocolGuid,
  870. (VOID **)&Private->PxeBcCallback
  871. );
  872. if (Status == EFI_UNSUPPORTED) {
  873. CopyMem (
  874. &Private->LoadFileCallback,
  875. &gPxeBcCallBackTemplate,
  876. sizeof (EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL)
  877. );
  878. //
  879. // Install a default callback if user didn't offer one.
  880. //
  881. Status = gBS->InstallProtocolInterface (
  882. Private->Mode.UsingIpv6 ? &Private->Ip6Nic->Controller : &Private->Ip4Nic->Controller,
  883. &gEfiPxeBaseCodeCallbackProtocolGuid,
  884. EFI_NATIVE_INTERFACE,
  885. &Private->LoadFileCallback
  886. );
  887. (*NewMakeCallback) = (BOOLEAN)(Status == EFI_SUCCESS);
  888. Status = PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, NewMakeCallback);
  889. if (EFI_ERROR (Status)) {
  890. PxeBc->Stop (PxeBc);
  891. return Status;
  892. }
  893. }
  894. return EFI_SUCCESS;
  895. }
  896. /**
  897. Uninstall PxeBaseCodeCallbackProtocol.
  898. @param[in] Private Pointer to PxeBc private data.
  899. @param[in] NewMakeCallback If TRUE, it is a new callback.
  900. Otherwise, it is not new callback.
  901. **/
  902. VOID
  903. PxeBcUninstallCallback (
  904. IN PXEBC_PRIVATE_DATA *Private,
  905. IN BOOLEAN NewMakeCallback
  906. )
  907. {
  908. EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
  909. PxeBc = &Private->PxeBc;
  910. if (NewMakeCallback) {
  911. NewMakeCallback = FALSE;
  912. PxeBc->SetParameters (PxeBc, NULL, NULL, NULL, NULL, &NewMakeCallback);
  913. gBS->UninstallProtocolInterface (
  914. Private->Mode.UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller,
  915. &gEfiPxeBaseCodeCallbackProtocolGuid,
  916. &Private->LoadFileCallback
  917. );
  918. }
  919. }
  920. /**
  921. Download one of boot file in the list, and it's special for IPv6.
  922. @param[in] Private Pointer to PxeBc private data.
  923. @param[in, out] BufferSize Size of user buffer for input;
  924. required buffer size for output.
  925. @param[in] Buffer Pointer to user buffer.
  926. @retval EFI_SUCCESS Read one of boot file in the list successfully.
  927. @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
  928. @retval EFI_NOT_FOUND There is no proper boot file available.
  929. @retval Others Failed to download boot file in the list.
  930. **/
  931. EFI_STATUS
  932. PxeBcReadBootFileList (
  933. IN PXEBC_PRIVATE_DATA *Private,
  934. IN OUT UINT64 *BufferSize,
  935. IN VOID *Buffer OPTIONAL
  936. )
  937. {
  938. EFI_STATUS Status;
  939. EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
  940. PxeBc = &Private->PxeBc;
  941. //
  942. // Try to download the boot file if everything is ready.
  943. //
  944. if (Buffer != NULL) {
  945. Status = PxeBc->Mtftp (
  946. PxeBc,
  947. EFI_PXE_BASE_CODE_TFTP_READ_FILE,
  948. Buffer,
  949. FALSE,
  950. BufferSize,
  951. &Private->BlockSize,
  952. &Private->ServerIp,
  953. Private->BootFileName,
  954. NULL,
  955. FALSE
  956. );
  957. } else {
  958. Status = EFI_BUFFER_TOO_SMALL;
  959. }
  960. return Status;
  961. }
  962. /**
  963. Load boot file into user buffer.
  964. @param[in] Private Pointer to PxeBc private data.
  965. @param[in, out] BufferSize Size of user buffer for input;
  966. required buffer size for output.
  967. @param[in] Buffer Pointer to user buffer.
  968. @retval EFI_SUCCESS Get all the boot information successfully.
  969. @retval EFI_BUFFER_TOO_SMALL The buffer size is not enough for boot file.
  970. @retval EFI_ABORTED User cancelled the current operation.
  971. @retval Others Failed to parse out the boot information.
  972. **/
  973. EFI_STATUS
  974. PxeBcLoadBootFile (
  975. IN PXEBC_PRIVATE_DATA *Private,
  976. IN OUT UINTN *BufferSize,
  977. IN VOID *Buffer OPTIONAL
  978. )
  979. {
  980. BOOLEAN NewMakeCallback;
  981. UINT64 RequiredSize;
  982. UINT64 CurrentSize;
  983. EFI_STATUS Status;
  984. EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
  985. EFI_PXE_BASE_CODE_MODE *PxeBcMode;
  986. NewMakeCallback = FALSE;
  987. PxeBc = &Private->PxeBc;
  988. PxeBcMode = &Private->Mode;
  989. CurrentSize = *BufferSize;
  990. RequiredSize = 0;
  991. //
  992. // Install pxebc callback protocol if hasn't been installed yet.
  993. //
  994. Status = PxeBcInstallCallback (Private, &NewMakeCallback);
  995. if (EFI_ERROR (Status)) {
  996. return Status;
  997. }
  998. if (Private->BootFileSize == 0) {
  999. //
  1000. // Discover the boot information about the bootfile if hasn't.
  1001. //
  1002. Status = PxeBcDiscoverBootFile (Private, &RequiredSize);
  1003. if (EFI_ERROR (Status)) {
  1004. goto ON_EXIT;
  1005. }
  1006. if (PXEBC_IS_SIZE_OVERFLOWED (RequiredSize)) {
  1007. //
  1008. // It's error if the required buffer size is beyond the system scope.
  1009. //
  1010. Status = EFI_DEVICE_ERROR;
  1011. goto ON_EXIT;
  1012. } else if (RequiredSize > 0) {
  1013. //
  1014. // Get the right buffer size of the bootfile required.
  1015. //
  1016. if ((CurrentSize < RequiredSize) || (Buffer == NULL)) {
  1017. //
  1018. // It's buffer too small if the size of user buffer is smaller than the required.
  1019. //
  1020. CurrentSize = RequiredSize;
  1021. Status = EFI_BUFFER_TOO_SMALL;
  1022. goto ON_EXIT;
  1023. }
  1024. CurrentSize = RequiredSize;
  1025. } else if ((RequiredSize == 0) && PxeBcMode->UsingIpv6) {
  1026. //
  1027. // Try to download another bootfile in list if failed to get the filesize of the last one.
  1028. // It's special for the case of IPv6.
  1029. //
  1030. Status = PxeBcReadBootFileList (Private, &CurrentSize, Buffer);
  1031. goto ON_EXIT;
  1032. }
  1033. } else if ((CurrentSize < Private->BootFileSize) || (Buffer == NULL)) {
  1034. //
  1035. // It's buffer too small if the size of user buffer is smaller than the required.
  1036. //
  1037. CurrentSize = Private->BootFileSize;
  1038. Status = EFI_BUFFER_TOO_SMALL;
  1039. goto ON_EXIT;
  1040. }
  1041. //
  1042. // Begin to download the bootfile if everything is ready.
  1043. //
  1044. AsciiPrint ("\n Downloading NBP file...\n");
  1045. if (PxeBcMode->UsingIpv6) {
  1046. Status = PxeBcReadBootFileList (
  1047. Private,
  1048. &CurrentSize,
  1049. Buffer
  1050. );
  1051. } else {
  1052. Status = PxeBc->Mtftp (
  1053. PxeBc,
  1054. EFI_PXE_BASE_CODE_TFTP_READ_FILE,
  1055. Buffer,
  1056. FALSE,
  1057. &CurrentSize,
  1058. &Private->BlockSize,
  1059. &Private->ServerIp,
  1060. Private->BootFileName,
  1061. NULL,
  1062. FALSE
  1063. );
  1064. }
  1065. ON_EXIT:
  1066. *BufferSize = (UINTN)CurrentSize;
  1067. PxeBcUninstallCallback (Private, NewMakeCallback);
  1068. if (Status == EFI_SUCCESS) {
  1069. AsciiPrint ("\n NBP file downloaded successfully.\n");
  1070. return EFI_SUCCESS;
  1071. } else if ((Status == EFI_BUFFER_TOO_SMALL) && (Buffer != NULL)) {
  1072. AsciiPrint ("\n PXE-E05: Buffer size is smaller than the requested file.\n");
  1073. } else if (Status == EFI_DEVICE_ERROR) {
  1074. AsciiPrint ("\n PXE-E07: Network device error.\n");
  1075. } else if (Status == EFI_OUT_OF_RESOURCES) {
  1076. AsciiPrint ("\n PXE-E09: Could not allocate I/O buffers.\n");
  1077. } else if (Status == EFI_NO_MEDIA) {
  1078. AsciiPrint ("\n PXE-E12: Could not detect network connection.\n");
  1079. } else if (Status == EFI_NO_RESPONSE) {
  1080. AsciiPrint ("\n PXE-E16: No valid offer received.\n");
  1081. } else if (Status == EFI_TIMEOUT) {
  1082. AsciiPrint ("\n PXE-E18: Server response timeout.\n");
  1083. } else if (Status == EFI_ABORTED) {
  1084. AsciiPrint ("\n PXE-E21: Remote boot cancelled.\n");
  1085. } else if (Status == EFI_ICMP_ERROR) {
  1086. AsciiPrint ("\n PXE-E22: Client received ICMP error from server.\n");
  1087. } else if (Status == EFI_TFTP_ERROR) {
  1088. AsciiPrint ("\n PXE-E23: Client received TFTP error from server.\n");
  1089. } else if (Status == EFI_NOT_FOUND) {
  1090. AsciiPrint ("\n PXE-E53: No boot filename received.\n");
  1091. } else if (Status != EFI_BUFFER_TOO_SMALL) {
  1092. AsciiPrint ("\n PXE-E99: Unexpected network error.\n");
  1093. }
  1094. return Status;
  1095. }