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