]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/PxeBcDxe/Pxe_loadfile.c
Import ArpDxe, Dhcp4Dxe, Ip4Dxe, Mtftp4Dxe, PxeBcDxe and PxeDhcp4Dxe.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / PxeBcDxe / Pxe_loadfile.c
1 /** @file
2
3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13 pxe_loadfile.c
14
15 Abstract:
16 An implementation of the load file protocol for network devices.
17
18
19 **/
20
21
22 #include "Bc.h"
23
24 #define DO_MENU (EFI_SUCCESS)
25 #define NO_MENU (DO_MENU + 1)
26 #define LOCAL_BOOT (EFI_ABORTED)
27 #define AUTO_SELECT (NO_MENU)
28
29 #define NUMBER_ROWS 25 // we set to mode 0
30 #define MAX_MENULIST 23
31
32 #define Ctl(x) (0x1F & (x))
33
34 typedef union {
35 DHCPV4_OP_STRUCT *OpPtr;
36 PXE_BOOT_MENU_ENTRY *CurrentMenuItemPtr;
37 PXE_OP_DISCOVERY_CONTROL *DiscCtlOpStr;
38 PXE_OP_BOOT_MENU *MenuPtr;
39 UINT8 *BytePtr;
40 } UNION_PTR;
41
42
43
44 /**
45 PxeBc callback routine for status updates and aborts.
46
47 @param This Pointer to PxeBcCallback
48 interface
49 @param Function PxeBc function ID#
50 @param Received Receive/transmit flag
51 @param PacketLength Length of received packet (0
52 == idle callback)
53 @param PacketPtr Pointer to received packet
54 (NULL == idle callback)
55
56 @retval EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE
57 EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT
58 -
59
60 **/
61 STATIC
62 EFI_PXE_BASE_CODE_CALLBACK_STATUS
63 EFIAPI
64 bc_callback (
65 IN EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL * This,
66 IN EFI_PXE_BASE_CODE_FUNCTION Function,
67 IN BOOLEAN Received,
68 IN UINT32 PacketLength,
69 IN EFI_PXE_BASE_CODE_PACKET * PacketPtr OPTIONAL
70 )
71 {
72 STATIC UINTN Propeller;
73
74 EFI_INPUT_KEY Key;
75 UINTN Row;
76 UINTN Col;
77
78 Propeller = 0;
79 //
80 // Resolve Warning 4 unreferenced parameter problem
81 //
82 This = This;
83
84 //
85 // Check for user abort.
86 //
87 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_SUCCESS) {
88 if (!Key.ScanCode) {
89 if (Key.UnicodeChar == Ctl ('c')) {
90 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
91 }
92 } else if (Key.ScanCode == SCAN_ESC) {
93 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_ABORT;
94 }
95 }
96 //
97 // Do nothing if this is a receive.
98 //
99 if (Received) {
100 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
101 }
102 //
103 // The display code is only for these functions.
104 //
105 switch (Function) {
106 case EFI_PXE_BASE_CODE_FUNCTION_MTFTP:
107 //
108 // If this is a transmit and not a M/TFTP open request,
109 // return now. Do not print a dot for each M/TFTP packet
110 // that is sent, only for the open packets.
111 //
112 if (PacketLength != 0 && PacketPtr != NULL) {
113 if (PacketPtr->Raw[0x1C] != 0x00 || PacketPtr->Raw[0x1D] != 0x01) {
114 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
115 }
116 }
117
118 break;
119
120 case EFI_PXE_BASE_CODE_FUNCTION_DHCP:
121 case EFI_PXE_BASE_CODE_FUNCTION_DISCOVER:
122 break;
123
124 default:
125 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
126 }
127 //
128 // Display routines
129 //
130 if (PacketLength != 0 && PacketPtr != NULL) {
131 //
132 // Display a '.' when a packet is transmitted.
133 //
134 AsciiPrint (".");
135 } else if (PacketLength == 0 && PacketPtr == NULL) {
136 //
137 // Display a propeller when waiting for packets if at
138 // least 200 ms have passed.
139 //
140 Row = gST->ConOut->Mode->CursorRow;
141 Col = gST->ConOut->Mode->CursorColumn;
142
143 AsciiPrint ("%c", "/-\\|"[Propeller]);
144 gST->ConOut->SetCursorPosition (gST->ConOut, Col, Row);
145
146 Propeller = (Propeller + 1) & 3;
147 }
148
149 return EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE;
150 }
151
152 STATIC EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL _bc_callback = {
153 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL_REVISION,
154 &bc_callback
155 };
156
157
158 /**
159 Display an IPv4 address in dot notation.
160
161 @param Ptr Pointer to IPv4 address.
162
163 @return None
164
165 **/
166 STATIC
167 VOID
168 PrintIpv4 (
169 UINT8 *Ptr
170 )
171 {
172 if (Ptr != NULL) {
173 AsciiPrint ("%d.%d.%d.%d", Ptr[0], Ptr[1], Ptr[2], Ptr[3]);
174 }
175 }
176
177
178 /**
179 Display client and server IP information.
180
181 @param Private Pointer to PxeBc interface
182
183 @return None
184
185 **/
186 STATIC
187 VOID
188 ShowMyInfo (
189 IN PXE_BASECODE_DEVICE *Private
190 )
191 {
192 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
193 UINTN Index;
194
195 //
196 // Do nothing if a NULL pointer is passed in.
197 //
198 if (Private == NULL) {
199 return ;
200 }
201 //
202 // Get pointer to PXE BaseCode mode structure
203 //
204 PxeBcMode = Private->EfiBc.Mode;
205
206 //
207 // Display client IP address
208 //
209 AsciiPrint ("\rCLIENT IP: ");
210 PrintIpv4 (PxeBcMode->StationIp.v4.Addr);
211
212 //
213 // Display subnet mask
214 //
215 AsciiPrint (" MASK: ");
216 PrintIpv4 (PxeBcMode->SubnetMask.v4.Addr);
217
218 //
219 // Display DHCP and proxyDHCP IP addresses
220 //
221 if (PxeBcMode->ProxyOfferReceived) {
222 AsciiPrint ("\nDHCP IP: ");
223 PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
224
225 AsciiPrint (" PROXY IP: ");
226 PrintIpv4 (((DHCPV4_OP_SERVER_IP *) PXE_OFFER_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
227 } else {
228 AsciiPrint (" DHCP IP: ");
229 PrintIpv4 (((DHCPV4_OP_SERVER_IP *) DHCPV4_ACK_BUFFER.OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1])->Ip.Addr);
230 }
231 //
232 // Display gateway IP addresses
233 //
234 for (Index = 0; Index < PxeBcMode->RouteTableEntries; ++Index) {
235 if ((Index % 3) == 0) {
236 AsciiPrint ("\r\nGATEWAY IP:");
237 }
238
239 AsciiPrint (" ");
240 PrintIpv4 (PxeBcMode->RouteTable[Index].GwAddr.v4.Addr);
241 AsciiPrint (" ");
242 }
243
244 AsciiPrint ("\n");
245 }
246
247
248 /**
249 Display prompt and wait for input.
250
251 @param Private Pointer to PxeBc interface
252 @param BootPromptPtr Pointer to PXE boot prompt
253 option
254
255 @retval AUTO_SELECT DO_MENU -
256 @retval NO_MENU
257 @retval LOCAL_BOOT
258
259 **/
260 STATIC
261 EFI_STATUS
262 DoPrompt (
263 PXE_BASECODE_DEVICE *Private,
264 PXE_OP_BOOT_PROMPT *BootPromptPtr
265 )
266 {
267 EFI_STATUS Status;
268 EFI_EVENT TimeoutEvent;
269 EFI_EVENT SecondsEvent;
270 INT32 SecColumn;
271 INT32 SecRow;
272 UINT8 SaveChar;
273 UINT8 SecsLeft;
274
275 //
276 // if auto select, just get right to it
277 //
278 if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_AUTO_SELECT) {
279 return AUTO_SELECT;
280 }
281 //
282 // if no timeout, go directly to display of menu
283 //
284 if (BootPromptPtr->Timeout == PXE_BOOT_PROMPT_NO_TIMEOUT) {
285 return DO_MENU;
286 }
287 //
288 //
289 //
290 Status = gBS->CreateEvent (
291 EVT_TIMER,
292 TPL_CALLBACK,
293 NULL,
294 NULL,
295 &TimeoutEvent
296 );
297
298 if (EFI_ERROR (Status)) {
299 return DO_MENU;
300 }
301
302 Status = gBS->SetTimer (
303 TimeoutEvent,
304 TimerRelative,
305 BootPromptPtr->Timeout * 10000000 + 100000
306 );
307
308 if (EFI_ERROR (Status)) {
309 gBS->CloseEvent (TimeoutEvent);
310 return DO_MENU;
311 }
312 //
313 //
314 //
315 Status = gBS->CreateEvent (
316 EVT_TIMER,
317 TPL_CALLBACK,
318 NULL,
319 NULL,
320 &SecondsEvent
321 );
322
323 if (EFI_ERROR (Status)) {
324 gBS->CloseEvent (TimeoutEvent);
325 return DO_MENU;
326 }
327
328 Status = gBS->SetTimer (
329 SecondsEvent,
330 TimerPeriodic,
331 10000000
332 ); /* 1 second */
333
334 if (EFI_ERROR (Status)) {
335 gBS->CloseEvent (SecondsEvent);
336 gBS->CloseEvent (TimeoutEvent);
337 return DO_MENU;
338 }
339 //
340 // display the prompt
341 // IMPORTANT! This prompt is an ASCII character string that may
342 // not be terminated with a NULL byte.
343 //
344 SaveChar = BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1];
345 BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = 0;
346
347 AsciiPrint ("%a ", BootPromptPtr->Prompt);
348 BootPromptPtr->Prompt[BootPromptPtr->Header.Length - 1] = SaveChar;
349
350 //
351 // wait until time expires or selection made - menu or local
352 //
353 SecColumn = gST->ConOut->Mode->CursorColumn;
354 SecRow = gST->ConOut->Mode->CursorRow;
355 SecsLeft = BootPromptPtr->Timeout;
356
357 gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
358 AsciiPrint ("(%d) ", SecsLeft);
359
360 //
361 // set the default action to be AUTO_SELECT
362 //
363 Status = AUTO_SELECT;
364
365 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
366 EFI_INPUT_KEY Key;
367
368 if (!EFI_ERROR (gBS->CheckEvent (SecondsEvent))) {
369 --SecsLeft;
370 gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
371 AsciiPrint ("(%d) ", SecsLeft);
372 }
373
374 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
375 UINT8 Buffer[512];
376 UINTN BufferSize;
377 EFI_STATUS Status;
378
379 BufferSize = sizeof Buffer;
380
381 Status = Private->EfiBc.UdpRead (
382 &Private->EfiBc,
383 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
384 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
385 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
386 NULL, /* dest ip */
387 NULL, /* dest port */
388 NULL, /* src ip */
389 NULL, /* src port */
390 NULL, /* hdr size */
391 NULL, /* hdr ptr */
392 &BufferSize,
393 Buffer
394 );
395
396 continue;
397 }
398
399 if (Key.ScanCode == 0) {
400 switch (Key.UnicodeChar) {
401 case Ctl ('c'):
402 Status = LOCAL_BOOT;
403 break;
404
405 case Ctl ('m'):
406 case 'm':
407 case 'M':
408 Status = DO_MENU;
409 break;
410
411 default:
412 continue;
413 }
414 } else {
415 switch (Key.ScanCode) {
416 case SCAN_F8:
417 Status = DO_MENU;
418 break;
419
420 case SCAN_ESC:
421 Status = LOCAL_BOOT;
422 break;
423
424 default:
425 continue;
426 }
427 }
428
429 break;
430 }
431
432 gBS->CloseEvent (SecondsEvent);
433 gBS->CloseEvent (TimeoutEvent);
434
435 gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
436 AsciiPrint (" ");
437
438 return Status;
439 }
440
441
442 /**
443 Display one menu item.
444
445 @param MenuItemPtr Pointer to PXE menu item
446 option.
447
448 @return None
449
450 **/
451 STATIC
452 VOID
453 PrintMenuItem (
454 PXE_BOOT_MENU_ENTRY *MenuItemPtr
455 )
456 {
457 UINT8 Length;
458 UINT8 SaveChar;
459
460 Length = (UINT8) MIN (70, MenuItemPtr->DataLen);
461 SaveChar = MenuItemPtr->Data[Length];
462
463 MenuItemPtr->Data[Length] = 0;
464 AsciiPrint (" %a\n", MenuItemPtr->Data);
465 MenuItemPtr->Data[Length] = SaveChar;
466 }
467
468
469 /**
470 Display and process menu.
471
472 @param Private Pointer to PxeBc interface
473 @param RxBufferPtr Pointer to receive buffer
474
475 @retval NO_MENU
476 @retval LOCAL_BOOT
477
478 **/
479 STATIC
480 EFI_STATUS
481 DoMenu (
482 PXE_BASECODE_DEVICE *Private,
483 DHCP_RECEIVE_BUFFER *RxBufferPtr
484 )
485 {
486 PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr;
487 PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST];
488 EFI_STATUS Status;
489 UNION_PTR Ptr;
490 UINTN SaveNumRte;
491 UINTN TopRow;
492 UINTN MenuLth;
493 UINTN NumMenuItems;
494 UINTN Index;
495 UINTN Longest;
496 UINTN Selected;
497 UINT16 Type;
498 UINT16 Layer;
499 BOOLEAN Done;
500
501 Selected = 0;
502 Layer = 0;
503
504 DEBUG ((DEBUG_WARN, "\nDoMenu() Enter."));
505
506 /* see if we have a menu/prompt */
507 if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {
508 DEBUG (
509 (DEBUG_WARN,
510 "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",
511 RxBufferPtr->OpAdds.Status)
512 );
513
514 return NO_MENU;
515 }
516
517 DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
518
519 //
520 // if not USE_BOOTFILE or no bootfile given, must have menu stuff
521 //
522 if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
523 DEBUG ((DEBUG_WARN, "\nDoMenu() DHCP w/ bootfile. "));
524 return NO_MENU;
525 }
526 //
527 // do prompt & menu if necessary
528 //
529 Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);
530
531 if (Status == LOCAL_BOOT) {
532 DEBUG ((DEBUG_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));
533
534 return Status;
535 }
536
537 Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
538
539 MenuLth = Ptr.MenuPtr->Header.Length;
540 Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem;
541
542 //
543 // build menu items array
544 //
545 for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems < MAX_MENULIST;) {
546 UINTN lth;
547
548 lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);
549
550 MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;
551
552 if (lth > Longest) {
553 //
554 // check if too long
555 //
556 if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {
557 Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));
558 }
559 }
560
561 Index += lth;
562 Ptr.BytePtr += lth;
563 }
564
565 if (Status != AUTO_SELECT) {
566 UINT8 BlankBuf[75];
567
568 SetMem (BlankBuf, sizeof BlankBuf, ' ');
569 BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;
570 AsciiPrint ("\n");
571
572 //
573 // now put up menu
574 //
575 for (Index = 0; Index < NumMenuItems; ++Index) {
576 PrintMenuItem (MenuItemPtrs[Index]);
577 }
578
579 TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;
580
581 //
582 // now wait for a selection
583 //
584 Done = FALSE;
585 do {
586 //
587 // highlight selection
588 //
589 EFI_INPUT_KEY Key;
590 UINTN NewSelected;
591
592 NewSelected = Selected;
593
594 //
595 // highlight selected row
596 //
597 gST->ConOut->SetAttribute (
598 gST->ConOut,
599 EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)
600 );
601 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);
602
603 AsciiPrint (" --->%a\r", BlankBuf);
604
605 PrintMenuItem (MenuItemPtrs[Selected]);
606 gST->ConOut->SetAttribute (
607 gST->ConOut,
608 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
609 );
610 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);
611
612 //
613 // wait for a keystroke
614 //
615 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
616 UINT8 TmpBuf[512];
617 UINTN TmpBufLen;
618
619 TmpBufLen = sizeof TmpBuf;
620
621 Private->EfiBc.UdpRead (
622 &Private->EfiBc,
623 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
624 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
625 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
626 NULL, /* dest ip */
627 NULL, /* dest port */
628 NULL, /* src ip */
629 NULL, /* src port */
630 NULL, /* hdr size */
631 NULL, /* hdr ptr */
632 &TmpBufLen,
633 TmpBuf
634 );
635 }
636
637 if (!Key.ScanCode) {
638 switch (Key.UnicodeChar) {
639 case Ctl ('c'):
640 Key.ScanCode = SCAN_ESC;
641 break;
642
643 case Ctl ('j'): /* linefeed */
644 case Ctl ('m'): /* return */
645 Done = TRUE;
646 break;
647
648 case Ctl ('i'): /* tab */
649 case ' ':
650 case 'd':
651 case 'D':
652 Key.ScanCode = SCAN_DOWN;
653 break;
654
655 case Ctl ('h'): /* backspace */
656 case 'u':
657 case 'U':
658 Key.ScanCode = SCAN_UP;
659 break;
660
661 default:
662 Key.ScanCode = 0;
663 }
664 }
665
666 switch (Key.ScanCode) {
667 case SCAN_LEFT:
668 case SCAN_UP:
669 if (NewSelected) {
670 --NewSelected;
671 }
672
673 break;
674
675 case SCAN_DOWN:
676 case SCAN_RIGHT:
677 if (++NewSelected == NumMenuItems) {
678 --NewSelected;
679 }
680
681 break;
682
683 case SCAN_PAGE_UP:
684 case SCAN_HOME:
685 NewSelected = 0;
686 break;
687
688 case SCAN_PAGE_DOWN:
689 case SCAN_END:
690 NewSelected = NumMenuItems - 1;
691 break;
692
693 case SCAN_ESC:
694 return LOCAL_BOOT;
695 }
696
697 /* unhighlight last selected row */
698 gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);
699
700 AsciiPrint ("%a\r", BlankBuf);
701
702 PrintMenuItem (MenuItemPtrs[Selected]);
703
704 Selected = NewSelected;
705 } while (!Done);
706 }
707
708 SaveNumRte = Private->EfiBc.Mode->RouteTableEntries;
709
710 Type = NTOHS (MenuItemPtrs[Selected]->Type);
711
712 if (Type == 0) {
713 DEBUG ((DEBUG_WARN, "\nDoMenu() Local boot selected. "));
714 return LOCAL_BOOT;
715 }
716
717 AsciiPrint ("Discover");
718
719 Status = Private->EfiBc.Discover (
720 &Private->EfiBc,
721 Type,
722 &Layer,
723 (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),
724 0
725 );
726
727 if (EFI_ERROR (Status)) {
728 AsciiPrint ("\r \r");
729
730 DEBUG (
731 (DEBUG_WARN,
732 "\nDoMenu() Return w/ %xh (%r).",
733 Status,
734 Status)
735 );
736
737 return Status;
738 }
739
740 AsciiPrint ("\rBOOT_SERVER_IP: ");
741 PrintIpv4 ((UINT8 *) &Private->ServerIp);
742
743 for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {
744 if ((Index % 3) == 0) {
745 AsciiPrint ("\r\nGATEWAY IP:");
746 }
747
748 AsciiPrint (" ");
749 PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);
750 AsciiPrint (" ");
751 }
752
753 AsciiPrint ("\n");
754
755 DEBUG ((DEBUG_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. "));
756
757 return EFI_SUCCESS;
758 }
759
760
761 /**
762 Get value 8- or 16-bit value from DHCP option.
763
764 @param OpPtr Pointer to DHCP option
765
766 @return Value from DHCP option
767
768 **/
769 STATIC
770 UINT16
771 GetValue (
772 DHCPV4_OP_STRUCT *OpPtr
773 )
774 {
775 if (OpPtr->Header.Length == 1) {
776 return OpPtr->Data[0];
777 } else {
778 return NTOHS (OpPtr->Data);
779 }
780 }
781
782
783 /**
784 Locate opcode in buffer.
785
786 @param BufferPtr Pointer to buffer
787 @param BufferLen Length of buffer
788 @param OpCode Option number
789
790 @return Pointer to opcode, may be NULL
791
792 **/
793 STATIC
794 UINT8 *
795 _PxeBcFindOpt (
796 UINT8 *BufferPtr,
797 UINTN BufferLen,
798 UINT8 OpCode
799 )
800 {
801 if (BufferPtr == NULL) {
802 return NULL;
803 }
804
805 while (BufferLen != 0) {
806 if (*BufferPtr == OpCode) {
807 return BufferPtr;
808 }
809
810 switch (*BufferPtr) {
811 case OP_END:
812 return NULL;
813
814 case OP_PAD:
815 ++BufferPtr;
816 --BufferLen;
817 continue;
818 }
819
820 if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {
821 return NULL;
822 }
823
824 BufferLen -= 2 + BufferPtr[1];
825 BufferPtr += 2 + BufferPtr[1];
826 }
827
828 return NULL;
829 }
830
831
832 /**
833 Find option in packet
834
835 @param PacketPtr Pointer to packet
836 @param OpCode option number
837
838 @return Pointer to option in packet
839
840 **/
841 STATIC
842 UINT8 *
843 PxeBcFindDhcpOpt (
844 EFI_PXE_BASE_CODE_PACKET *PacketPtr,
845 UINT8 OpCode
846 )
847 {
848 UINTN PacketLen;
849 UINT8 Overload;
850 UINT8 *OptionBufferPtr;
851
852 //
853 //
854 //
855 PacketLen = 380;
856 Overload = 0;
857
858 //
859 // Figure size of DHCP option space.
860 //
861 OptionBufferPtr = _PxeBcFindOpt (
862 PacketPtr->Dhcpv4.DhcpOptions,
863 380,
864 OP_DHCP_MAX_MESSAGE_SZ
865 );
866
867 if (OptionBufferPtr != NULL) {
868 if (OptionBufferPtr[1] == 2) {
869 UINT16 n;
870
871 CopyMem (&n, &OptionBufferPtr[2], 2);
872 PacketLen = HTONS (n);
873
874 if (PacketLen < sizeof (EFI_PXE_BASE_CODE_DHCPV4_PACKET)) {
875 PacketLen = 380;
876 } else {
877 PacketLen -= (PacketPtr->Dhcpv4.DhcpOptions - &PacketPtr->Dhcpv4.BootpOpcode) + 28;
878 }
879 }
880 }
881 //
882 // Look for option overloading.
883 //
884 OptionBufferPtr = _PxeBcFindOpt (
885 PacketPtr->Dhcpv4.DhcpOptions,
886 PacketLen,
887 OP_DHCP_OPTION_OVERLOAD
888 );
889
890 if (OptionBufferPtr != NULL) {
891 if (OptionBufferPtr[1] == 1) {
892 Overload = OptionBufferPtr[2];
893 }
894 }
895 //
896 // Look for caller's option.
897 //
898 OptionBufferPtr = _PxeBcFindOpt (
899 PacketPtr->Dhcpv4.DhcpOptions,
900 PacketLen,
901 OpCode
902 );
903
904 if (OptionBufferPtr != NULL) {
905 return OptionBufferPtr;
906 }
907
908 if (Overload & OVLD_FILE) {
909 OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpBootFile, 128, OpCode);
910
911 if (OptionBufferPtr != NULL) {
912 return OptionBufferPtr;
913 }
914 }
915
916 if (Overload & OVLD_SRVR_NAME) {
917 OptionBufferPtr = _PxeBcFindOpt (PacketPtr->Dhcpv4.BootpSrvName, 64, OpCode);
918
919 if (OptionBufferPtr != NULL) {
920 return OptionBufferPtr;
921 }
922 }
923
924 return NULL;
925 }
926
927
928 /**
929 Download file into buffer
930
931 @param Private Pointer to PxeBc interface
932 @param BufferSize pointer to size of download
933 buffer
934 @param Buffer Pointer to buffer
935
936 @return EFI_BUFFER_TOO_SMALL -
937 @return EFI_NOT_FOUND -
938 @return EFI_PROTOCOL_ERROR -
939
940 **/
941 STATIC
942 EFI_STATUS
943 DownloadFile (
944 IN PXE_BASECODE_DEVICE *Private,
945 IN OUT UINT64 *BufferSize,
946 IN VOID *Buffer
947 )
948 {
949 EFI_PXE_BASE_CODE_MTFTP_INFO MtftpInfo;
950 EFI_PXE_BASE_CODE_TFTP_OPCODE OpCode;
951 DHCP_RECEIVE_BUFFER *RxBuf;
952 EFI_STATUS Status;
953 UINTN BlockSize;
954
955 RxBuf = (DHCP_RECEIVE_BUFFER *) Private->BootServerReceiveBuffer;
956 BlockSize = 0x8000;
957
958 DEBUG ((EFI_D_WARN, "\nDownloadFile() Enter."));
959
960 if (Buffer == NULL || *BufferSize == 0 || *BufferSize < Private->FileSize) {
961 if (Private->FileSize != 0) {
962 *BufferSize = Private->FileSize;
963 return EFI_BUFFER_TOO_SMALL;
964 }
965
966 AsciiPrint ("\nTSize");
967
968 OpCode = EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE;
969 } else if (RxBuf->OpAdds.Status & WfM11a_TYPE) {
970 OpCode = EFI_PXE_BASE_CODE_MTFTP_READ_FILE;
971
972 ZeroMem (&MtftpInfo, sizeof MtftpInfo);
973
974 *(IPV4_ADDR *) &MtftpInfo.MCastIp = *(IPV4_ADDR *) RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_IP - 1]->Data;
975
976 CopyMem (
977 &MtftpInfo.CPort,
978 RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_CPORT - 1]->Data,
979 sizeof MtftpInfo.CPort
980 );
981
982 CopyMem (
983 &MtftpInfo.SPort,
984 RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_SPORT - 1]->Data,
985 sizeof MtftpInfo.SPort
986 );
987
988 MtftpInfo.ListenTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_TMOUT - 1]);
989
990 MtftpInfo.TransmitTimeout = GetValue (RxBuf->OpAdds.PxeOptAdds[VEND_PXE_MTFTP_DELAY - 1]);
991
992 AsciiPrint ("\nMTFTP");
993 } else {
994 AsciiPrint ("\nTFTP");
995
996 OpCode = EFI_PXE_BASE_CODE_TFTP_READ_FILE;
997 }
998
999 Private->FileSize = 0;
1000
1001 RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data[RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Header.Length] = 0;
1002
1003 Status = Private->EfiBc.Mtftp (
1004 &Private->EfiBc,
1005 OpCode,
1006 Buffer,
1007 FALSE,
1008 BufferSize,
1009 &BlockSize,
1010 &Private->ServerIp,
1011 (UINT8 *) RxBuf->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]->Data,
1012 &MtftpInfo,
1013 FALSE
1014 );
1015
1016 if (Status != EFI_SUCCESS && Status != EFI_BUFFER_TOO_SMALL) {
1017 DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #1 %Xh", Status));
1018 return Status;
1019 }
1020
1021 if (sizeof (UINTN) < sizeof (UINT64) && *BufferSize > 0xFFFFFFFF) {
1022 Private->FileSize = 0xFFFFFFFF;
1023 } else {
1024 Private->FileSize = (UINTN) *BufferSize;
1025 }
1026
1027 if (OpCode == EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE) {
1028 DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #2"));
1029 return EFI_BUFFER_TOO_SMALL;
1030 }
1031
1032 if (EFI_ERROR (Status)) {
1033 DEBUG ((DEBUG_WARN, "\nDownloadFile() Exit #3 %Xh", Status));
1034 return Status;
1035 }
1036
1037 if (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected && Private->EfiBc.Mode->PxeBisReplyReceived) {
1038 UINT64 CredentialLen;
1039 UINTN BlockSize;
1040 UINT8 CredentialFilename[256];
1041 UINT8 *op;
1042 VOID *CredentialBuffer;
1043
1044 //
1045 // Get name of credential file. It may be in the BOOTP
1046 // bootfile field or a DHCP option.
1047 //
1048 ZeroMem (CredentialFilename, sizeof CredentialFilename);
1049
1050 op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);
1051
1052 if (op != NULL) {
1053 if (op[1] == 0) {
1054 /* No credential filename */
1055 return EFI_NOT_FOUND;
1056 }
1057
1058 CopyMem (CredentialFilename, &op[2], op[1]);
1059 } else {
1060 if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {
1061 /* No credential filename */
1062 return EFI_NOT_FOUND;
1063 }
1064
1065 CopyMem (CredentialFilename, &op[2], 128);
1066 }
1067 //
1068 // Get size of credential file. It may be available as a
1069 // DHCP option. If not, use the TFTP get file size.
1070 //
1071 CredentialLen = 0;
1072
1073 op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);
1074
1075 if (op != NULL) {
1076 /*
1077 * This is actually the size of the credential file
1078 * buffer. The actual credential file size will be
1079 * returned when we download the file.
1080 */
1081 if (op[1] == 2) {
1082 UINT16 n;
1083
1084 CopyMem (&n, &op[2], 2);
1085 CredentialLen = HTONS (n) * 512;
1086 }
1087 }
1088
1089 if (CredentialLen == 0) {
1090 BlockSize = 8192;
1091
1092 Status = Private->EfiBc.Mtftp (
1093 &Private->EfiBc,
1094 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
1095 NULL,
1096 FALSE,
1097 &CredentialLen,
1098 &BlockSize,
1099 &Private->ServerIp,
1100 CredentialFilename,
1101 NULL,
1102 FALSE
1103 );
1104
1105 if (EFI_ERROR (Status)) {
1106 return Status;
1107 }
1108
1109 if (CredentialLen == 0) {
1110 //
1111 // %%TBD -- EFI error for invalid credential
1112 // file.
1113 //
1114 return EFI_PROTOCOL_ERROR;
1115 }
1116 }
1117 //
1118 // Allocate credential file buffer.
1119 //
1120 Status = gBS->AllocatePool (
1121 EfiBootServicesData,
1122 (UINTN) CredentialLen,
1123 &CredentialBuffer
1124 );
1125
1126 if (EFI_ERROR (Status)) {
1127 return Status;
1128 }
1129 //
1130 // Download credential file.
1131 //
1132 BlockSize = 8192;
1133
1134 Status = Private->EfiBc.Mtftp (
1135 &Private->EfiBc,
1136 EFI_PXE_BASE_CODE_TFTP_READ_FILE,
1137 CredentialBuffer,
1138 FALSE,
1139 &CredentialLen,
1140 &BlockSize,
1141 &Private->ServerIp,
1142 CredentialFilename,
1143 NULL,
1144 FALSE
1145 );
1146
1147 if (EFI_ERROR (Status)) {
1148 gBS->FreePool (CredentialBuffer);
1149 return Status;
1150 }
1151 //
1152 // Verify credentials.
1153 //
1154 if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {
1155 Status = EFI_SUCCESS;
1156 } else {
1157 //
1158 // %%TBD -- An EFI error code for failing credential verification.
1159 //
1160 Status = EFI_PROTOCOL_ERROR;
1161 }
1162
1163 gBS->FreePool (CredentialBuffer);
1164 }
1165
1166 return Status;
1167 }
1168
1169
1170 /**
1171 Start PXE DHCP. Get DHCP and proxyDHCP information.
1172 Display remote boot menu and prompt. Select item from menu.
1173
1174 @param Private Pointer to PxeBc interface
1175 @param BufferSize Pointer to download buffer
1176 size
1177 @param Buffer Pointer to download buffer
1178
1179 @retval EFI_SUCCESS
1180 @retval EFI_NOT_READY
1181
1182 **/
1183 STATIC
1184 EFI_STATUS
1185 LoadfileStart (
1186 IN PXE_BASECODE_DEVICE *Private,
1187 IN OUT UINT64 *BufferSize,
1188 IN VOID *Buffer
1189 )
1190 {
1191 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
1192 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
1193 EFI_SIMPLE_NETWORK_MODE *SnpMode;
1194 EFI_STATUS Status;
1195 VOID *RxBuf;
1196
1197 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Enter."));
1198
1199 //
1200 // Try to start BaseCode, for now only IPv4 is supported
1201 // so don't try to start using IPv6.
1202 //
1203 Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);
1204
1205 if (EFI_ERROR (Status)) {
1206 if (Status != EFI_ALREADY_STARTED) {
1207 DEBUG ((DEBUG_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status));
1208 return Status;
1209 }
1210 }
1211 //
1212 // Get pointers to PXE mode structure, SNP protocol structure
1213 // and SNP mode structure.
1214 //
1215 PxeBcMode = Private->EfiBc.Mode;
1216 Snp = Private->SimpleNetwork;
1217 SnpMode = Snp->Mode;
1218
1219 //
1220 // Display client MAC address, like 16-bit PXE ROMs
1221 //
1222 AsciiPrint ("\nCLIENT MAC ADDR: ");
1223
1224 {
1225 UINTN Index;
1226 UINTN hlen;
1227
1228 hlen = SnpMode->HwAddressSize;
1229
1230 for (Index = 0; Index < hlen; ++Index) {
1231 AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);
1232 }
1233 }
1234
1235 AsciiPrint ("\nDHCP");
1236
1237 Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);
1238
1239 if (EFI_ERROR (Status)) {
1240 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status));
1241 AsciiPrint ("\r \r");
1242 return Status;
1243 }
1244
1245 ShowMyInfo (Private);
1246
1247 RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
1248 #define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)
1249
1250 Status = DoMenu (Private, RxBufferPtr);
1251
1252 if (Status == EFI_SUCCESS) {
1253 //
1254 // did a discovery - take info from discovery packet
1255 //
1256 RxBuf = &PXE_ACK_BUFFER;
1257 } else if (Status == NO_MENU) {
1258 //
1259 // did not do a discovery - take info from rxbuf
1260 //
1261 Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;
1262
1263 if (!(Private->ServerIp.Addr[0])) {
1264 *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;
1265 }
1266 } else {
1267 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status));
1268 return Status;
1269 }
1270
1271 if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1272 DEBUG ((DEBUG_WARN, "\nLoadfileStart() Exit Not ready?"));
1273 return EFI_NOT_READY;
1274 }
1275 //
1276 // check for file size option sent
1277 //
1278 if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {
1279 Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);
1280 }
1281
1282 Private->BootServerReceiveBuffer = RxBufferPtr;
1283
1284 Status = DownloadFile (Private, BufferSize, Buffer);
1285
1286 DEBUG (
1287 (DEBUG_WARN,
1288 "\nLoadfileStart() Exit. DownloadFile() = %Xh",
1289 Status)
1290 );
1291
1292 return Status;
1293 }
1294
1295
1296 /**
1297 Loadfile interface for PxeBc interface
1298
1299 @param This Pointer to Loadfile interface
1300 @param FilePath Not used and not checked
1301 @param BootPolicy Must be TRUE
1302 @param BufferSize Pointer to buffer size
1303 @param Buffer Pointer to download buffer or
1304 NULL
1305
1306 @return EFI_INVALID_PARAMETER -
1307 @return EFI_UNSUPPORTED -
1308 @return EFI_SUCCESS -
1309 @return EFI_BUFFER_TOO_SMALL -
1310
1311 **/
1312 EFI_STATUS
1313 EFIAPI
1314 LoadFile (
1315 IN EFI_LOAD_FILE_PROTOCOL *This,
1316 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1317 IN BOOLEAN BootPolicy,
1318 IN OUT UINTN *BufferSize,
1319 IN OUT VOID *Buffer
1320 )
1321 {
1322 LOADFILE_DEVICE *LoadfilePtr;
1323 UINT64 TmpBufSz;
1324 INT32 OrigMode;
1325 INT32 OrigAttribute;
1326 BOOLEAN RemoveCallback;
1327 BOOLEAN NewMakeCallback;
1328 EFI_STATUS Status;
1329 EFI_STATUS TempStatus;
1330 //
1331 //
1332 //
1333 OrigMode = gST->ConOut->Mode->Mode;
1334 OrigAttribute = gST->ConOut->Mode->Attribute;
1335 RemoveCallback = FALSE;
1336
1337 AsciiPrint ("Running LoadFile()\n");
1338
1339 //
1340 // Resolve Warning 4 unreferenced parameter problem
1341 //
1342 FilePath = NULL;
1343
1344 //
1345 // If either if these parameters are NULL, we cannot continue.
1346 //
1347 if (This == NULL || BufferSize == NULL) {
1348 DEBUG ((DEBUG_WARN, "\nLoadFile() This or BufferSize == NULL"));
1349 return EFI_INVALID_PARAMETER;
1350 }
1351 //
1352 // We only support BootPolicy == TRUE
1353 //
1354 if (!BootPolicy) {
1355 DEBUG ((DEBUG_WARN, "\nLoadFile() BootPolicy == FALSE"));
1356 return EFI_UNSUPPORTED;
1357 }
1358 //
1359 // Get pointer to LoadFile protocol structure.
1360 //
1361 LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);
1362
1363 if (LoadfilePtr == NULL) {
1364 DEBUG (
1365 (DEBUG_NET,
1366 "\nLoadFile() Could not get pointer to LoadFile structure")
1367 );
1368 return EFI_INVALID_PARAMETER;
1369 }
1370 //
1371 // Lock interface
1372 //
1373 EfiAcquireLock (&LoadfilePtr->Lock);
1374
1375 //
1376 // Set console output mode and display attribute
1377 //
1378 if (OrigMode != 0) {
1379 gST->ConOut->SetMode (gST->ConOut, 0);
1380 }
1381
1382 gST->ConOut->SetAttribute (
1383 gST->ConOut,
1384 EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)
1385 );
1386
1387 //
1388 // See if BaseCode already has a Callback protocol attached.
1389 // If there is none, attach our own Callback protocol.
1390 //
1391 Status = gBS->HandleProtocol (
1392 LoadfilePtr->Private->Handle,
1393 &gEfiPxeBaseCodeCallbackProtocolGuid,
1394 (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr
1395 );
1396
1397 if (Status == EFI_SUCCESS) {
1398 //
1399 // There is already a callback routine. Do nothing.
1400 //
1401 DEBUG ((DEBUG_WARN, "\nLoadFile() BC callback exists."));
1402
1403 } else if (Status == EFI_UNSUPPORTED) {
1404 //
1405 // No BaseCode Callback protocol found. Add our own.
1406 //
1407 Status = gBS->InstallProtocolInterface (
1408 &LoadfilePtr->Private->Handle,
1409 &gEfiPxeBaseCodeCallbackProtocolGuid,
1410 EFI_NATIVE_INTERFACE,
1411 &_bc_callback
1412 );
1413
1414 DEBUG ((DEBUG_WARN, "\nLoadFile() Callback install status == %xh", Status));
1415
1416 RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);
1417
1418 if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {
1419 NewMakeCallback = TRUE;
1420 LoadfilePtr->Private->EfiBc.SetParameters (
1421 &LoadfilePtr->Private->EfiBc,
1422 NULL,
1423 NULL,
1424 NULL,
1425 NULL,
1426 &NewMakeCallback
1427 );
1428 }
1429
1430 } else {
1431 DEBUG ((DEBUG_WARN, "\nLoadFile() Callback check status == %xh", Status));
1432 }
1433 //
1434 // Check for starting or for continuing after already getting
1435 // the file size.
1436 //
1437 if (LoadfilePtr->Private->FileSize == 0) {
1438 TmpBufSz = 0;
1439 Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);
1440
1441 if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {
1442 *BufferSize = 0xFFFFFFFF;
1443 } else {
1444 *BufferSize = (UINTN) TmpBufSz;
1445 }
1446
1447 if (Status == EFI_BUFFER_TOO_SMALL) {
1448 //
1449 // This is done so loadfile will work even if the boot manager
1450 // did not make the first call with Buffer == NULL.
1451 //
1452 Buffer = NULL;
1453 }
1454 } else if (Buffer == NULL) {
1455 DEBUG ((DEBUG_WARN, "\nLoadfile() Get buffer size"));
1456
1457 //
1458 // Continuing from previous LoadFile request. Make sure there
1459 // is a buffer and that it is big enough.
1460 //
1461 *BufferSize = LoadfilePtr->Private->FileSize;
1462 Status = EFI_BUFFER_TOO_SMALL;
1463 } else {
1464 DEBUG ((DEBUG_WARN, "\nLoadFile() Download file"));
1465
1466 //
1467 // Everything looks good, try to download the file.
1468 //
1469 TmpBufSz = *BufferSize;
1470 Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);
1471
1472 //
1473 // Next call to loadfile will start DHCP process again.
1474 //
1475 LoadfilePtr->Private->FileSize = 0;
1476 }
1477 //
1478 // If we added a callback protocol, now is the time to remove it.
1479 //
1480 if (RemoveCallback) {
1481 NewMakeCallback = FALSE;
1482 TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (
1483 &LoadfilePtr->Private->EfiBc,
1484 NULL,
1485 NULL,
1486 NULL,
1487 NULL,
1488 &NewMakeCallback
1489 );
1490
1491 if (TempStatus == EFI_SUCCESS) {
1492 gBS->UninstallProtocolInterface (
1493 LoadfilePtr->Private->Handle,
1494 &gEfiPxeBaseCodeCallbackProtocolGuid,
1495 &_bc_callback
1496 );
1497 }
1498 }
1499 //
1500 // Restore display mode and attribute
1501 //
1502 if (OrigMode != 0) {
1503 gST->ConOut->SetMode (gST->ConOut, OrigMode);
1504 }
1505
1506 gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);
1507
1508 //
1509 // Unlock interface
1510 //
1511 EfiReleaseLock (&LoadfilePtr->Lock);
1512
1513 DEBUG ((DEBUG_WARN, "\nBC.Loadfile() Status == %xh\n", Status));
1514
1515 if (Status == EFI_SUCCESS) {
1516 return EFI_SUCCESS;
1517
1518 } else if (Status == EFI_BUFFER_TOO_SMALL) {
1519 //
1520 // Error is only displayed when we are actually trying to
1521 // download the boot image.
1522 //
1523 if (Buffer == NULL) {
1524 return EFI_BUFFER_TOO_SMALL;
1525 }
1526
1527 AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");
1528
1529 } else if (Status == EFI_DEVICE_ERROR) {
1530 AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");
1531
1532 } else if (Status == EFI_OUT_OF_RESOURCES) {
1533 AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");
1534
1535 } else if (Status == EFI_NO_MEDIA) {
1536 AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");
1537
1538 } else if (Status == EFI_NO_RESPONSE) {
1539 AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");
1540
1541 } else if (Status == EFI_TIMEOUT) {
1542 AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");
1543
1544 } else if (Status == EFI_ABORTED) {
1545 AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");
1546
1547 } else if (Status == EFI_ICMP_ERROR) {
1548 AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");
1549
1550 if (LoadfilePtr->Private->EfiBc.Mode != NULL) {
1551 if (LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {
1552
1553 AsciiPrint (
1554 "PXE-E98: Type: %xh Code: %xh ",
1555 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,
1556 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code
1557 );
1558
1559 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {
1560 case 0x03:
1561 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {
1562 case 0x00: /* net unreachable */
1563 AsciiPrint ("Net unreachable");
1564 break;
1565
1566 case 0x01: /* host unreachable */
1567 AsciiPrint ("Host unreachable");
1568 break;
1569
1570 case 0x02: /* protocol unreachable */
1571 AsciiPrint ("Protocol unreachable");
1572 break;
1573
1574 case 0x03: /* port unreachable */
1575 AsciiPrint ("Port unreachable");
1576 break;
1577
1578 case 0x04: /* Fragmentation needed */
1579 AsciiPrint ("Fragmentation needed");
1580 break;
1581
1582 case 0x05: /* Source route failed */
1583 AsciiPrint ("Source route failed");
1584 break;
1585 }
1586
1587 break;
1588 }
1589
1590 AsciiPrint ("\n");
1591 }
1592 }
1593
1594 } else if (Status == EFI_TFTP_ERROR) {
1595 AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");
1596
1597 if (LoadfilePtr->Private->EfiBc.Mode != NULL) {
1598 if (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived) {
1599 AsciiPrint (
1600 "PXE-E98: Code: %xh %a\n",
1601 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,
1602 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString
1603 );
1604 }
1605 }
1606
1607 } else {
1608 AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);
1609 }
1610
1611 LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);
1612
1613 return Status;
1614 }