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