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