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