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