]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c
3dceefb945cd275fd688743365c045cb7ca349a3
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_loadfile.c
1 /*++
2
3 Copyright (c) 2006 - 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 #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
397 BufferSize = sizeof Buffer;
398
399 Private->EfiBc.UdpRead (
400 &Private->EfiBc,
401 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
402 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
403 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
404 NULL, /* dest ip */
405 NULL, /* dest port */
406 NULL, /* src ip */
407 NULL, /* src port */
408 NULL, /* hdr size */
409 NULL, /* hdr ptr */
410 &BufferSize,
411 Buffer
412 );
413
414 continue;
415 }
416
417 if (Key.ScanCode == 0) {
418 switch (Key.UnicodeChar) {
419 case Ctl ('c'):
420 Status = LOCAL_BOOT;
421 break;
422
423 case Ctl ('m'):
424 case 'm':
425 case 'M':
426 Status = DO_MENU;
427 break;
428
429 default:
430 continue;
431 }
432 } else {
433 switch (Key.ScanCode) {
434 case SCAN_F8:
435 Status = DO_MENU;
436 break;
437
438 case SCAN_ESC:
439 Status = LOCAL_BOOT;
440 break;
441
442 default:
443 continue;
444 }
445 }
446
447 break;
448 }
449
450 gBS->CloseEvent (SecondsEvent);
451 gBS->CloseEvent (TimeoutEvent);
452
453 gST->ConOut->SetCursorPosition (gST->ConOut, SecColumn, SecRow);
454 AsciiPrint (" ");
455
456 return Status;
457 }
458
459 STATIC
460 VOID
461 PrintMenuItem (
462 PXE_BOOT_MENU_ENTRY *MenuItemPtr
463 )
464 /*++
465
466 Routine Description:
467
468 Display one menu item.
469
470 Arguments:
471
472 MenuItemPtr - Pointer to PXE menu item option.
473
474 Returns:
475
476 None
477
478 --*/
479 {
480 UINT8 Length;
481 UINT8 SaveChar;
482
483 Length = (UINT8) EFI_MIN (70, MenuItemPtr->DataLen);
484 SaveChar = MenuItemPtr->Data[Length];
485
486 MenuItemPtr->Data[Length] = 0;
487 AsciiPrint (" %a\n", MenuItemPtr->Data);
488 MenuItemPtr->Data[Length] = SaveChar;
489 }
490
491 STATIC
492 EFI_STATUS
493 DoMenu (
494 PXE_BASECODE_DEVICE *Private,
495 DHCP_RECEIVE_BUFFER *RxBufferPtr
496 )
497 /*++
498
499 Routine Description:
500
501 Display and process menu.
502
503 Arguments:
504
505 Private - Pointer to PxeBc interface
506 RxBufferPtr - Pointer to receive buffer
507
508 Returns:
509
510 NO_MENU -
511 LOCAL_BOOT -
512
513 --*/
514 {
515 PXE_OP_DISCOVERY_CONTROL *DiscoveryControlPtr;
516 PXE_BOOT_MENU_ENTRY *MenuItemPtrs[MAX_MENULIST];
517 EFI_STATUS Status;
518 UNION_PTR Ptr;
519 UINTN SaveNumRte;
520 UINTN TopRow;
521 UINTN MenuLth;
522 UINTN NumMenuItems;
523 UINTN Index;
524 UINTN Longest;
525 UINTN Selected;
526 UINT16 Type;
527 UINT16 Layer;
528 BOOLEAN Done;
529
530 Selected = 0;
531 Layer = 0;
532
533 DEBUG ((EFI_D_WARN, "\nDoMenu() Enter."));
534
535 /* see if we have a menu/prompt */
536 if (!(RxBufferPtr->OpAdds.Status & DISCOVER_TYPE)) {
537 DEBUG (
538 (EFI_D_WARN,
539 "\nDoMenu() No menu/prompt info. OpAdds.Status == %xh ",
540 RxBufferPtr->OpAdds.Status)
541 );
542
543 return NO_MENU;
544 }
545
546 DiscoveryControlPtr = (PXE_OP_DISCOVERY_CONTROL *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_DISCOVERY_CONTROL_IX - 1];
547
548 //
549 // if not USE_BOOTFILE or no bootfile given, must have menu stuff
550 //
551 if ((DiscoveryControlPtr->ControlBits & USE_BOOTFILE) && RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
552 DEBUG ((EFI_D_WARN, "\nDoMenu() DHCP w/ bootfile. "));
553 return NO_MENU;
554 }
555 //
556 // do prompt & menu if necessary
557 //
558 Status = DoPrompt (Private, (PXE_OP_BOOT_PROMPT *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_PROMPT_IX - 1]);
559
560 if (Status == LOCAL_BOOT) {
561 DEBUG ((EFI_D_WARN, "\nDoMenu() DoPrompt() returned LOCAL_BOOT. "));
562
563 return Status;
564 }
565
566 Ptr.BytePtr = (UINT8 *) RxBufferPtr->OpAdds.PxeOptAdds[VEND_PXE_BOOT_MENU_IX - 1];
567
568 MenuLth = Ptr.MenuPtr->Header.Length;
569 Ptr.CurrentMenuItemPtr = Ptr.MenuPtr->MenuItem;
570
571 //
572 // build menu items array
573 //
574 for (Longest = NumMenuItems = Index = 0; Index < MenuLth && NumMenuItems <= MAX_MENULIST;) {
575 UINTN lth;
576
577 lth = Ptr.CurrentMenuItemPtr->DataLen + sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data);
578
579 MenuItemPtrs[NumMenuItems++] = Ptr.CurrentMenuItemPtr;
580
581 if (lth > Longest) {
582 //
583 // check if too long
584 //
585 if ((Longest = lth) > 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))) {
586 Longest = 70 + (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data));
587 }
588 }
589
590 Index += lth;
591 Ptr.BytePtr += lth;
592 }
593
594 if (Status != AUTO_SELECT) {
595 UINT8 BlankBuf[75];
596
597 SetMem (BlankBuf, sizeof BlankBuf, ' ');
598 BlankBuf[Longest + 5 - (sizeof (*Ptr.CurrentMenuItemPtr) - sizeof (Ptr.CurrentMenuItemPtr->Data))] = 0;
599 AsciiPrint ("\n");
600
601 //
602 // now put up menu
603 //
604 for (Index = 0; Index < NumMenuItems; ++Index) {
605 PrintMenuItem (MenuItemPtrs[Index]);
606 }
607
608 TopRow = gST->ConOut->Mode->CursorRow - NumMenuItems;
609
610 //
611 // now wait for a selection
612 //
613 Done = FALSE;
614 do {
615 //
616 // highlight selection
617 //
618 EFI_INPUT_KEY Key;
619 UINTN NewSelected;
620
621 NewSelected = Selected;
622
623 //
624 // highlight selected row
625 //
626 gST->ConOut->SetAttribute (
627 gST->ConOut,
628 EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY)
629 );
630 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Selected);
631
632 AsciiPrint (" --->%a\r", BlankBuf);
633
634 PrintMenuItem (MenuItemPtrs[Selected]);
635 gST->ConOut->SetAttribute (
636 gST->ConOut,
637 EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK)
638 );
639 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + NumMenuItems);
640
641 //
642 // wait for a keystroke
643 //
644 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &Key) == EFI_NOT_READY) {
645 UINT8 TmpBuf[512];
646 UINTN TmpBufLen;
647
648 TmpBufLen = sizeof TmpBuf;
649
650 Private->EfiBc.UdpRead (
651 &Private->EfiBc,
652 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP |
653 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT |
654 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT,
655 NULL, /* dest ip */
656 NULL, /* dest port */
657 NULL, /* src ip */
658 NULL, /* src port */
659 NULL, /* hdr size */
660 NULL, /* hdr ptr */
661 &TmpBufLen,
662 TmpBuf
663 );
664 }
665
666 if (!Key.ScanCode) {
667 switch (Key.UnicodeChar) {
668 case Ctl ('c'):
669 Key.ScanCode = SCAN_ESC;
670 break;
671
672 case Ctl ('j'): /* linefeed */
673 case Ctl ('m'): /* return */
674 Done = TRUE;
675 break;
676
677 case Ctl ('i'): /* tab */
678 case ' ':
679 case 'd':
680 case 'D':
681 Key.ScanCode = SCAN_DOWN;
682 break;
683
684 case Ctl ('h'): /* backspace */
685 case 'u':
686 case 'U':
687 Key.ScanCode = SCAN_UP;
688 break;
689
690 default:
691 Key.ScanCode = 0;
692 }
693 }
694
695 switch (Key.ScanCode) {
696 case SCAN_LEFT:
697 case SCAN_UP:
698 if (NewSelected) {
699 --NewSelected;
700 }
701
702 break;
703
704 case SCAN_DOWN:
705 case SCAN_RIGHT:
706 if (++NewSelected == NumMenuItems) {
707 --NewSelected;
708 }
709
710 break;
711
712 case SCAN_PAGE_UP:
713 case SCAN_HOME:
714 NewSelected = 0;
715 break;
716
717 case SCAN_PAGE_DOWN:
718 case SCAN_END:
719 NewSelected = NumMenuItems - 1;
720 break;
721
722 case SCAN_ESC:
723 return LOCAL_BOOT;
724 }
725
726 /* unhighlight last selected row */
727 gST->ConOut->SetCursorPosition (gST->ConOut, 5, TopRow + Selected);
728
729 AsciiPrint ("%a\r", BlankBuf);
730
731 PrintMenuItem (MenuItemPtrs[Selected]);
732
733 Selected = NewSelected;
734 } while (!Done);
735 }
736
737 SaveNumRte = Private->EfiBc.Mode->RouteTableEntries;
738
739 Type = NTOHS (MenuItemPtrs[Selected]->Type);
740
741 if (Type == 0) {
742 DEBUG ((EFI_D_WARN, "\nDoMenu() Local boot selected. "));
743 return LOCAL_BOOT;
744 }
745
746 AsciiPrint ("Discover");
747
748 Status = Private->EfiBc.Discover (
749 &Private->EfiBc,
750 Type,
751 &Layer,
752 (BOOLEAN) (Private->EfiBc.Mode->BisSupported && Private->EfiBc.Mode->BisDetected),
753 0
754 );
755
756 if (EFI_ERROR (Status)) {
757 AsciiPrint ("\r \r");
758
759 DEBUG (
760 (EFI_D_WARN,
761 "\nDoMenu() Return w/ %xh (%r).",
762 Status,
763 Status)
764 );
765
766 return Status;
767 }
768
769 AsciiPrint ("\rBOOT_SERVER_IP: ");
770 PrintIpv4 ((UINT8 *) &Private->ServerIp);
771
772 for (Index = SaveNumRte; Index < Private->EfiBc.Mode->RouteTableEntries; ++Index) {
773 if ((Index % 3) == 0) {
774 AsciiPrint ("\r\nGATEWAY IP:");
775 }
776
777 AsciiPrint (" ");
778 PrintIpv4 ((UINT8 *) &Private->EfiBc.Mode->RouteTable[Index].GwAddr);
779 AsciiPrint (" ");
780 }
781
782 AsciiPrint ("\n");
783
784 DEBUG ((EFI_D_WARN, "\nDoMenu() Return w/ EFI_SUCCESS. "));
785
786 return EFI_SUCCESS;
787 }
788
789 STATIC
790 UINT16
791 GetValue (
792 DHCPV4_OP_STRUCT *OpPtr
793 )
794 /*++
795
796 Routine Description:
797
798 Get value 8- or 16-bit value from DHCP option.
799
800 Arguments:
801
802 OpPtr - Pointer to DHCP option
803
804 Returns:
805
806 Value from DHCP option
807
808 --*/
809 {
810 if (OpPtr->Header.Length == 1) {
811 return OpPtr->Data[0];
812 } else {
813 return NTOHS (OpPtr->Data);
814 }
815 }
816
817 STATIC
818 UINT8 *
819 _PxeBcFindOpt (
820 UINT8 *BufferPtr,
821 UINTN BufferLen,
822 UINT8 OpCode
823 )
824 /*++
825
826 Routine Description:
827
828 Locate opcode in buffer.
829
830 Arguments:
831
832 BufferPtr - Pointer to buffer
833 BufferLen - Length of buffer
834 OpCode - Option number
835
836 Returns:
837
838 Pointer to opcode, may be NULL
839
840 --*/
841 {
842 if (BufferPtr == NULL) {
843 return NULL;
844 }
845
846 while (BufferLen != 0) {
847 if (*BufferPtr == OpCode) {
848 return BufferPtr;
849 }
850
851 switch (*BufferPtr) {
852 case OP_END:
853 return NULL;
854
855 case OP_PAD:
856 ++BufferPtr;
857 --BufferLen;
858 continue;
859 }
860
861 if ((UINTN) BufferLen <= (UINTN) 2 + BufferPtr[1]) {
862 return NULL;
863 }
864
865 BufferLen -= 2 + BufferPtr[1];
866 BufferPtr += 2 + BufferPtr[1];
867 }
868
869 return NULL;
870 }
871
872 STATIC
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 UINT8 CredentialFilename[256];
1092 UINT8 *op;
1093 VOID *CredentialBuffer;
1094
1095 //
1096 // Get name of credential file. It may be in the BOOTP
1097 // bootfile field or a DHCP option.
1098 //
1099 ZeroMem (CredentialFilename, sizeof CredentialFilename);
1100
1101 op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_DHCP_BOOTFILE);
1102
1103 if (op != NULL) {
1104 if (op[1] == 0) {
1105 /* No credential filename */
1106 return EFI_NOT_FOUND;
1107 }
1108
1109 CopyMem (CredentialFilename, &op[2], op[1]);
1110 } else {
1111 if (Private->EfiBc.Mode->PxeBisReply.Dhcpv4.BootpBootFile[0] == 0) {
1112 /* No credential filename */
1113 return EFI_NOT_FOUND;
1114 }
1115
1116 CopyMem (CredentialFilename, &op[2], 128);
1117 }
1118 //
1119 // Get size of credential file. It may be available as a
1120 // DHCP option. If not, use the TFTP get file size.
1121 //
1122 CredentialLen = 0;
1123
1124 op = PxeBcFindDhcpOpt (&Private->EfiBc.Mode->PxeBisReply, OP_BOOT_FILE_SZ);
1125
1126 if (op != NULL) {
1127 /*
1128 * This is actually the size of the credential file
1129 * buffer. The actual credential file size will be
1130 * returned when we download the file.
1131 */
1132 if (op[1] == 2) {
1133 UINT16 n;
1134
1135 CopyMem (&n, &op[2], 2);
1136 CredentialLen = HTONS (n) * 512;
1137 }
1138 }
1139
1140 if (CredentialLen == 0) {
1141 BlockSize = 8192;
1142
1143 Status = Private->EfiBc.Mtftp (
1144 &Private->EfiBc,
1145 EFI_PXE_BASE_CODE_TFTP_GET_FILE_SIZE,
1146 NULL,
1147 FALSE,
1148 &CredentialLen,
1149 &BlockSize,
1150 &Private->ServerIp,
1151 CredentialFilename,
1152 NULL,
1153 FALSE
1154 );
1155
1156 if (EFI_ERROR (Status)) {
1157 return Status;
1158 }
1159
1160 if (CredentialLen == 0) {
1161 //
1162 // %%TBD -- EFI error for invalid credential
1163 // file.
1164 //
1165 return EFI_PROTOCOL_ERROR;
1166 }
1167 }
1168 //
1169 // Allocate credential file buffer.
1170 //
1171 CredentialBuffer = AllocatePool ((UINTN) CredentialLen);
1172 if (CredentialBuffer == NULL) {
1173 return EFI_OUT_OF_RESOURCES;
1174 }
1175 //
1176 // Download credential file.
1177 //
1178 BlockSize = 8192;
1179
1180 Status = Private->EfiBc.Mtftp (
1181 &Private->EfiBc,
1182 EFI_PXE_BASE_CODE_TFTP_READ_FILE,
1183 CredentialBuffer,
1184 FALSE,
1185 &CredentialLen,
1186 &BlockSize,
1187 &Private->ServerIp,
1188 CredentialFilename,
1189 NULL,
1190 FALSE
1191 );
1192
1193 if (EFI_ERROR (Status)) {
1194 FreePool (CredentialBuffer);
1195 return Status;
1196 }
1197 //
1198 // Verify credentials.
1199 //
1200 if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {
1201 Status = EFI_SUCCESS;
1202 } else {
1203 //
1204 // %%TBD -- An EFI error code for failing credential verification.
1205 //
1206 Status = EFI_PROTOCOL_ERROR;
1207 }
1208
1209 FreePool (CredentialBuffer);
1210 }
1211
1212 return Status;
1213 }
1214
1215 STATIC
1216 EFI_STATUS
1217 LoadfileStart (
1218 IN PXE_BASECODE_DEVICE *Private,
1219 IN OUT UINT64 *BufferSize,
1220 IN VOID *Buffer
1221 )
1222 /*++
1223
1224 Routine Description:
1225
1226 Start PXE DHCP. Get DHCP and proxyDHCP information.
1227 Display remote boot menu and prompt. Select item from menu.
1228
1229 Arguments:
1230
1231 Private - Pointer to PxeBc interface
1232 BufferSize - Pointer to download buffer size
1233 Buffer - Pointer to download buffer
1234
1235 Returns:
1236
1237 EFI_SUCCESS -
1238 EFI_NOT_READY -
1239
1240 --*/
1241 {
1242 EFI_PXE_BASE_CODE_MODE *PxeBcMode;
1243 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
1244 EFI_SIMPLE_NETWORK_MODE *SnpMode;
1245 EFI_STATUS Status;
1246 VOID *RxBuf;
1247
1248 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Enter."));
1249
1250 //
1251 // Try to start BaseCode, for now only IPv4 is supported
1252 // so don't try to start using IPv6.
1253 //
1254 Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);
1255
1256 if (EFI_ERROR (Status)) {
1257 if (Status != EFI_ALREADY_STARTED) {
1258 DEBUG ((EFI_D_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status));
1259 return Status;
1260 }
1261 }
1262 //
1263 // Get pointers to PXE mode structure, SNP protocol structure
1264 // and SNP mode structure.
1265 //
1266 PxeBcMode = Private->EfiBc.Mode;
1267 Snp = Private->SimpleNetwork;
1268 SnpMode = Snp->Mode;
1269
1270 //
1271 // Display client MAC address, like 16-bit PXE ROMs
1272 //
1273 AsciiPrint ("\nCLIENT MAC ADDR: ");
1274
1275 {
1276 UINTN Index;
1277 UINTN hlen;
1278
1279 hlen = SnpMode->HwAddressSize;
1280
1281 for (Index = 0; Index < hlen; ++Index) {
1282 AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);
1283 }
1284 }
1285
1286 AsciiPrint ("\nDHCP");
1287
1288 Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);
1289
1290 if (EFI_ERROR (Status)) {
1291 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status));
1292 AsciiPrint ("\r \r");
1293 return Status;
1294 }
1295
1296 ShowMyInfo (Private);
1297
1298 RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;
1299 #define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)
1300
1301 Status = DoMenu (Private, RxBufferPtr);
1302
1303 if (Status == EFI_SUCCESS) {
1304 //
1305 // did a discovery - take info from discovery packet
1306 //
1307 RxBuf = &PXE_ACK_BUFFER;
1308 } else if (Status == NO_MENU) {
1309 //
1310 // did not do a discovery - take info from rxbuf
1311 //
1312 Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;
1313
1314 if (!(Private->ServerIp.Addr[0])) {
1315 *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;
1316 }
1317 } else {
1318 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status));
1319 return Status;
1320 }
1321
1322 if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {
1323 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit Not ready?"));
1324 return EFI_NOT_READY;
1325 }
1326 //
1327 // check for file size option sent
1328 //
1329 if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {
1330 Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);
1331 }
1332
1333 Private->BootServerReceiveBuffer = RxBufferPtr;
1334
1335 Status = DownloadFile (Private, BufferSize, Buffer);
1336
1337 DEBUG (
1338 (EFI_D_WARN,
1339 "\nLoadfileStart() Exit. DownloadFile() = %Xh",
1340 Status)
1341 );
1342
1343 return Status;
1344 }
1345
1346 EFI_STATUS
1347 EFIAPI
1348 LoadFile (
1349 IN EFI_LOAD_FILE_PROTOCOL *This,
1350 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
1351 IN BOOLEAN BootPolicy,
1352 IN OUT UINTN *BufferSize,
1353 IN OUT VOID *Buffer
1354 )
1355 /*++
1356
1357 Routine Description:
1358
1359 Loadfile interface for PxeBc interface
1360
1361 Arguments:
1362
1363 This - Pointer to Loadfile interface
1364 FilePath - Not used and not checked
1365 BootPolicy - Must be TRUE
1366 BufferSize - Pointer to buffer size
1367 Buffer - Pointer to download buffer or NULL
1368
1369 Returns:
1370
1371 EFI_INVALID_PARAMETER -
1372 EFI_UNSUPPORTED -
1373 EFI_SUCCESS -
1374 EFI_BUFFER_TOO_SMALL -
1375
1376 --*/
1377 {
1378 LOADFILE_DEVICE *LoadfilePtr;
1379 UINT64 TmpBufSz;
1380 INT32 OrigMode;
1381 INT32 OrigAttribute;
1382 BOOLEAN RemoveCallback;
1383 BOOLEAN NewMakeCallback;
1384 EFI_STATUS Status;
1385 EFI_STATUS TempStatus;
1386 //
1387 //
1388 //
1389 OrigMode = gST->ConOut->Mode->Mode;
1390 OrigAttribute = gST->ConOut->Mode->Attribute;
1391 RemoveCallback = FALSE;
1392
1393 AsciiPrint ("Running LoadFile()\n");
1394
1395 //
1396 // If either if these parameters are NULL, we cannot continue.
1397 //
1398 if (This == NULL || BufferSize == NULL) {
1399 DEBUG ((EFI_D_WARN, "\nLoadFile() This or BufferSize == NULL"));
1400 return EFI_INVALID_PARAMETER;
1401 }
1402 //
1403 // We only support BootPolicy == TRUE
1404 //
1405 if (!BootPolicy) {
1406 DEBUG ((EFI_D_WARN, "\nLoadFile() BootPolicy == FALSE"));
1407 return EFI_UNSUPPORTED;
1408 }
1409 //
1410 // Get pointer to LoadFile protocol structure.
1411 //
1412 LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);
1413
1414 if (LoadfilePtr == NULL) {
1415 DEBUG (
1416 (EFI_D_NET,
1417 "\nLoadFile() Could not get pointer to LoadFile structure")
1418 );
1419 return EFI_INVALID_PARAMETER;
1420 }
1421 //
1422 // Lock interface
1423 //
1424 EfiAcquireLock (&LoadfilePtr->Lock);
1425
1426 //
1427 // Set console output mode and display attribute
1428 //
1429 if (OrigMode != 0) {
1430 gST->ConOut->SetMode (gST->ConOut, 0);
1431 }
1432
1433 gST->ConOut->SetAttribute (
1434 gST->ConOut,
1435 EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)
1436 );
1437
1438 //
1439 // See if BaseCode already has a Callback protocol attached.
1440 // If there is none, attach our own Callback protocol.
1441 //
1442 Status = gBS->HandleProtocol (
1443 LoadfilePtr->Private->Handle,
1444 &gEfiPxeBaseCodeCallbackProtocolGuid,
1445 (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr
1446 );
1447
1448 if (Status == EFI_SUCCESS) {
1449 //
1450 // There is already a callback routine. Do nothing.
1451 //
1452 DEBUG ((EFI_D_WARN, "\nLoadFile() BC callback exists."));
1453 } else if (Status == EFI_UNSUPPORTED) {
1454 //
1455 // No BaseCode Callback protocol found. Add our own.
1456 //
1457 Status = gBS->InstallProtocolInterface (
1458 &LoadfilePtr->Private->Handle,
1459 &gEfiPxeBaseCodeCallbackProtocolGuid,
1460 EFI_NATIVE_INTERFACE,
1461 &_bc_callback
1462 );
1463
1464 DEBUG ((EFI_D_WARN, "\nLoadFile() Callback install status == %xh", Status));
1465
1466 RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);
1467
1468 if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {
1469 NewMakeCallback = TRUE;
1470 LoadfilePtr->Private->EfiBc.SetParameters (
1471 &LoadfilePtr->Private->EfiBc,
1472 NULL,
1473 NULL,
1474 NULL,
1475 NULL,
1476 &NewMakeCallback
1477 );
1478 }
1479 } else {
1480 DEBUG ((EFI_D_WARN, "\nLoadFile() Callback check status == %xh", Status));
1481 }
1482 //
1483 // Check for starting or for continuing after already getting
1484 // the file size.
1485 //
1486 if (LoadfilePtr->Private->FileSize == 0) {
1487 TmpBufSz = 0;
1488 Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);
1489
1490 if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {
1491 *BufferSize = 0xFFFFFFFF;
1492 } else {
1493 *BufferSize = (UINTN) TmpBufSz;
1494 }
1495
1496 if (Status == EFI_BUFFER_TOO_SMALL) {
1497 //
1498 // This is done so loadfile will work even if the boot manager
1499 // did not make the first call with Buffer == NULL.
1500 //
1501 Buffer = NULL;
1502 }
1503 } else if (Buffer == NULL) {
1504 DEBUG ((EFI_D_WARN, "\nLoadfile() Get buffer size"));
1505
1506 //
1507 // Continuing from previous LoadFile request. Make sure there
1508 // is a buffer and that it is big enough.
1509 //
1510 *BufferSize = LoadfilePtr->Private->FileSize;
1511 Status = EFI_BUFFER_TOO_SMALL;
1512 } else {
1513 DEBUG ((EFI_D_WARN, "\nLoadFile() Download file"));
1514
1515 //
1516 // Everything looks good, try to download the file.
1517 //
1518 TmpBufSz = *BufferSize;
1519 Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);
1520
1521 //
1522 // Next call to loadfile will start DHCP process again.
1523 //
1524 LoadfilePtr->Private->FileSize = 0;
1525 }
1526 //
1527 // If we added a callback protocol, now is the time to remove it.
1528 //
1529 if (RemoveCallback) {
1530 NewMakeCallback = FALSE;
1531 TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (
1532 &LoadfilePtr->Private->EfiBc,
1533 NULL,
1534 NULL,
1535 NULL,
1536 NULL,
1537 &NewMakeCallback
1538 );
1539
1540 if (TempStatus == EFI_SUCCESS) {
1541 gBS->UninstallProtocolInterface (
1542 LoadfilePtr->Private->Handle,
1543 &gEfiPxeBaseCodeCallbackProtocolGuid,
1544 &_bc_callback
1545 );
1546 }
1547 }
1548 //
1549 // Restore display mode and attribute
1550 //
1551 if (OrigMode != 0) {
1552 gST->ConOut->SetMode (gST->ConOut, OrigMode);
1553 }
1554
1555 gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);
1556
1557 //
1558 // Unlock interface
1559 //
1560 EfiReleaseLock (&LoadfilePtr->Lock);
1561
1562 DEBUG ((EFI_D_WARN, "\nBC.Loadfile() Status == %xh\n", Status));
1563
1564 if (Status == EFI_SUCCESS) {
1565 /* 0 */
1566 return EFI_SUCCESS;
1567 } else if (Status == EFI_BUFFER_TOO_SMALL) {
1568 /* 5 */
1569 //
1570 // Error is only displayed when we are actually trying to
1571 // download the boot image.
1572 //
1573 if (Buffer == NULL) {
1574 return EFI_BUFFER_TOO_SMALL;
1575 }
1576 AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");
1577 } else if (Status == EFI_DEVICE_ERROR) {
1578 /* 7 */
1579 AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");
1580 } else if (Status == EFI_OUT_OF_RESOURCES) {
1581 /* 9 */
1582 AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");
1583 } else if (Status == EFI_NO_MEDIA) {
1584 /* 12 */
1585 AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");
1586 } else if (Status == EFI_NO_RESPONSE) {
1587 /* 16 */
1588 AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");
1589 } else if (Status == EFI_TIMEOUT) {
1590 /* 18 */
1591 AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");
1592 } else if (Status == EFI_ABORTED) {
1593 /* 21 */
1594 AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");
1595 } else if (Status == EFI_ICMP_ERROR) {
1596 /* 22 */
1597 AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");
1598
1599 if ((LoadfilePtr->Private->EfiBc.Mode != NULL) && LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {
1600 AsciiPrint (
1601 "PXE-E98: Type: %xh Code: %xh ",
1602 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,
1603 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code
1604 );
1605
1606 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {
1607 case 0x03:
1608 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {
1609 case 0x00: /* net unreachable */
1610 AsciiPrint ("Net unreachable");
1611 break;
1612
1613 case 0x01: /* host unreachable */
1614 AsciiPrint ("Host unreachable");
1615 break;
1616
1617 case 0x02: /* protocol unreachable */
1618 AsciiPrint ("Protocol unreachable");
1619 break;
1620
1621 case 0x03: /* port unreachable */
1622 AsciiPrint ("Port unreachable");
1623 break;
1624
1625 case 0x04: /* Fragmentation needed */
1626 AsciiPrint ("Fragmentation needed");
1627 break;
1628
1629 case 0x05: /* Source route failed */
1630 AsciiPrint ("Source route failed");
1631 break;
1632 }
1633
1634 break;
1635 }
1636
1637 AsciiPrint ("\n");
1638 }
1639 } else if (Status == EFI_TFTP_ERROR) {
1640 /* 23 */
1641 AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");
1642
1643 if ((LoadfilePtr->Private->EfiBc.Mode != NULL) && (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived)) {
1644 AsciiPrint (
1645 "PXE-E98: Code: %xh %a\n",
1646 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,
1647 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString
1648 );
1649 }
1650 } else {
1651 AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);
1652 }
1653
1654 LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);
1655
1656 return Status;
1657 }