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