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