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