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