]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Network/PxeBc/Dxe/pxe_loadfile.c
Clean up the following module msa files, they are three networt and two PCD modules.
[mirror_edk2.git] / EdkModulePkg / Universal / Network / PxeBc / Dxe / pxe_loadfile.c
CommitLineData
878ddf1f 1/*++\r
2\r
26aa0c2f 3Copyright (c) 2006 - 2007, Intel Corporation \r
878ddf1f 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
26aa0c2f
LG
1171 CredentialBuffer = AllocatePool ((UINTN) CredentialLen);\r
1172 if (CredentialBuffer == NULL) {\r
1173 return EFI_OUT_OF_RESOURCES;\r
878ddf1f 1174 }\r
1175 //\r
1176 // Download credential file.\r
1177 //\r
1178 BlockSize = 8192;\r
1179\r
1180 Status = Private->EfiBc.Mtftp (\r
1181 &Private->EfiBc,\r
1182 EFI_PXE_BASE_CODE_TFTP_READ_FILE,\r
1183 CredentialBuffer,\r
1184 FALSE,\r
1185 &CredentialLen,\r
1186 &BlockSize,\r
1187 &Private->ServerIp,\r
1188 CredentialFilename,\r
1189 NULL,\r
1190 FALSE\r
1191 );\r
1192\r
1193 if (EFI_ERROR (Status)) {\r
26aa0c2f 1194 FreePool (CredentialBuffer);\r
878ddf1f 1195 return Status;\r
1196 }\r
1197 //\r
1198 // Verify credentials.\r
1199 //\r
1200 if (PxebcBisVerify (Private, Buffer, Private->FileSize, CredentialBuffer, (UINTN) CredentialLen)) {\r
1201 Status = EFI_SUCCESS;\r
1202 } else {\r
1203 //\r
1204 // %%TBD -- An EFI error code for failing credential verification.\r
1205 //\r
1206 Status = EFI_PROTOCOL_ERROR;\r
1207 }\r
1208\r
26aa0c2f 1209 FreePool (CredentialBuffer);\r
878ddf1f 1210 }\r
1211\r
1212 return Status;\r
1213}\r
1214\r
1215STATIC\r
1216EFI_STATUS\r
1217LoadfileStart (\r
1218 IN PXE_BASECODE_DEVICE *Private,\r
1219 IN OUT UINT64 *BufferSize,\r
1220 IN VOID *Buffer\r
1221 )\r
1222/*++\r
1223\r
1224Routine Description:\r
1225\r
1226 Start PXE DHCP. Get DHCP and proxyDHCP information.\r
1227 Display remote boot menu and prompt. Select item from menu.\r
1228\r
1229Arguments:\r
1230\r
1231 Private - Pointer to PxeBc interface\r
1232 BufferSize - Pointer to download buffer size\r
1233 Buffer - Pointer to download buffer\r
1234\r
1235Returns:\r
1236\r
1237 EFI_SUCCESS - \r
1238 EFI_NOT_READY - \r
1239 \r
1240--*/\r
1241{\r
1242 EFI_PXE_BASE_CODE_MODE *PxeBcMode;\r
1243 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
1244 EFI_SIMPLE_NETWORK_MODE *SnpMode;\r
1245 EFI_STATUS Status;\r
1246 VOID *RxBuf;\r
1247\r
1248 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Enter."));\r
1249\r
1250 //\r
1251 // Try to start BaseCode, for now only IPv4 is supported\r
1252 // so don't try to start using IPv6.\r
1253 //\r
1254 Status = Private->EfiBc.Start (&Private->EfiBc, FALSE);\r
1255\r
1256 if (EFI_ERROR (Status)) {\r
1257 if (Status != EFI_ALREADY_STARTED) {\r
1258 DEBUG ((EFI_D_NET, "\nLoadfileStart() Exit BC.Start() == %xh", Status));\r
1259 return Status;\r
1260 }\r
1261 }\r
1262 //\r
1263 // Get pointers to PXE mode structure, SNP protocol structure\r
1264 // and SNP mode structure.\r
1265 //\r
1266 PxeBcMode = Private->EfiBc.Mode;\r
1267 Snp = Private->SimpleNetwork;\r
1268 SnpMode = Snp->Mode;\r
1269\r
1270 //\r
1271 // Display client MAC address, like 16-bit PXE ROMs\r
1272 //\r
1273 AsciiPrint ("\nCLIENT MAC ADDR: ");\r
1274\r
1275 {\r
1276 UINTN Index;\r
1277 UINTN hlen;\r
1278\r
1279 hlen = SnpMode->HwAddressSize;\r
1280\r
1281 for (Index = 0; Index < hlen; ++Index) {\r
1282 AsciiPrint ("%02x ", SnpMode->CurrentAddress.Addr[Index]);\r
1283 }\r
1284 }\r
1285\r
1286 AsciiPrint ("\nDHCP");\r
1287\r
1288 Status = Private->EfiBc.Dhcp (&Private->EfiBc, TRUE);\r
1289\r
1290 if (EFI_ERROR (Status)) {\r
1291 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit BC.Dhcp() == %Xh", Status));\r
1292 AsciiPrint ("\r \r");\r
1293 return Status;\r
1294 }\r
1295\r
1296 ShowMyInfo (Private);\r
1297\r
1298 RxBuf = PxeBcMode->ProxyOfferReceived ? &PXE_OFFER_BUFFER : &DHCPV4_ACK_BUFFER;\r
1299#define RxBufferPtr ((DHCP_RECEIVE_BUFFER *) RxBuf)\r
1300\r
1301 Status = DoMenu (Private, RxBufferPtr);\r
1302\r
1303 if (Status == EFI_SUCCESS) {\r
1304 //\r
1305 // did a discovery - take info from discovery packet\r
1306 //\r
1307 RxBuf = &PXE_ACK_BUFFER;\r
1308 } else if (Status == NO_MENU) {\r
1309 //\r
1310 // did not do a discovery - take info from rxbuf\r
1311 //\r
1312 Private->ServerIp.Addr[0] = RxBufferPtr->u.Dhcpv4.siaddr;\r
1313\r
1314 if (!(Private->ServerIp.Addr[0])) {\r
1315 *(IPV4_ADDR *) &Private->ServerIp = *(IPV4_ADDR *) RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_SERVER_IP_IX - 1]->Data;\r
1316 }\r
1317 } else {\r
1318 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit DoMenu() == %Xh", Status));\r
1319 return Status;\r
1320 }\r
1321\r
1322 if (!RxBufferPtr->OpAdds.PktOptAdds[OP_DHCP_BOOTFILE_IX - 1]) {\r
1323 DEBUG ((EFI_D_WARN, "\nLoadfileStart() Exit Not ready?"));\r
1324 return EFI_NOT_READY;\r
1325 }\r
1326 //\r
1327 // check for file size option sent\r
1328 //\r
1329 if (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]) {\r
1330 Private->FileSize = 512 * NTOHS (RxBufferPtr->OpAdds.PktOptAdds[OP_BOOT_FILE_SZ_IX - 1]->Data);\r
1331 }\r
1332\r
1333 Private->BootServerReceiveBuffer = RxBufferPtr;\r
1334\r
1335 Status = DownloadFile (Private, BufferSize, Buffer);\r
1336\r
1337 DEBUG (\r
1338 (EFI_D_WARN,\r
1339 "\nLoadfileStart() Exit. DownloadFile() = %Xh",\r
1340 Status)\r
1341 );\r
1342\r
1343 return Status;\r
1344}\r
1345\r
1346EFI_STATUS\r
1347EFIAPI\r
1348LoadFile (\r
1349 IN EFI_LOAD_FILE_PROTOCOL *This,\r
1350 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
1351 IN BOOLEAN BootPolicy,\r
1352 IN OUT UINTN *BufferSize,\r
1353 IN OUT VOID *Buffer\r
1354 )\r
1355/*++\r
1356\r
1357Routine Description:\r
1358\r
1359 Loadfile interface for PxeBc interface\r
1360\r
1361Arguments:\r
1362\r
1363 This - Pointer to Loadfile interface\r
1364 FilePath - Not used and not checked\r
1365 BootPolicy - Must be TRUE\r
1366 BufferSize - Pointer to buffer size \r
1367 Buffer - Pointer to download buffer or NULL\r
1368\r
1369Returns:\r
1370\r
1371 EFI_INVALID_PARAMETER -\r
1372 EFI_UNSUPPORTED -\r
1373 EFI_SUCCESS -\r
1374 EFI_BUFFER_TOO_SMALL -\r
1375\r
1376--*/\r
1377{\r
1378 LOADFILE_DEVICE *LoadfilePtr;\r
1379 UINT64 TmpBufSz;\r
1380 INT32 OrigMode;\r
1381 INT32 OrigAttribute;\r
1382 BOOLEAN RemoveCallback;\r
1383 BOOLEAN NewMakeCallback;\r
1384 EFI_STATUS Status;\r
1385 EFI_STATUS TempStatus;\r
1386 //\r
1387 //\r
1388 //\r
1389 OrigMode = gST->ConOut->Mode->Mode;\r
1390 OrigAttribute = gST->ConOut->Mode->Attribute;\r
1391 RemoveCallback = FALSE;\r
1392\r
1393 AsciiPrint ("Running LoadFile()\n");\r
1394\r
878ddf1f 1395 //\r
1396 // If either if these parameters are NULL, we cannot continue.\r
1397 //\r
1398 if (This == NULL || BufferSize == NULL) {\r
1399 DEBUG ((EFI_D_WARN, "\nLoadFile() This or BufferSize == NULL"));\r
1400 return EFI_INVALID_PARAMETER;\r
1401 }\r
1402 //\r
1403 // We only support BootPolicy == TRUE\r
1404 //\r
1405 if (!BootPolicy) {\r
1406 DEBUG ((EFI_D_WARN, "\nLoadFile() BootPolicy == FALSE"));\r
1407 return EFI_UNSUPPORTED;\r
1408 }\r
1409 //\r
1410 // Get pointer to LoadFile protocol structure.\r
1411 //\r
1412 LoadfilePtr = CR (This, LOADFILE_DEVICE, LoadFile, LOADFILE_DEVICE_SIGNATURE);\r
1413\r
1414 if (LoadfilePtr == NULL) {\r
1415 DEBUG (\r
1416 (EFI_D_NET,\r
1417 "\nLoadFile() Could not get pointer to LoadFile structure")\r
1418 );\r
1419 return EFI_INVALID_PARAMETER;\r
1420 }\r
1421 //\r
1422 // Lock interface\r
1423 //\r
1424 EfiAcquireLock (&LoadfilePtr->Lock);\r
1425\r
1426 //\r
1427 // Set console output mode and display attribute\r
1428 //\r
1429 if (OrigMode != 0) {\r
1430 gST->ConOut->SetMode (gST->ConOut, 0);\r
1431 }\r
1432\r
1433 gST->ConOut->SetAttribute (\r
1434 gST->ConOut,\r
1435 EFI_TEXT_ATTR (EFI_LIGHTGRAY,EFI_BLACK)\r
1436 );\r
1437\r
1438 //\r
1439 // See if BaseCode already has a Callback protocol attached.\r
1440 // If there is none, attach our own Callback protocol.\r
1441 //\r
1442 Status = gBS->HandleProtocol (\r
1443 LoadfilePtr->Private->Handle,\r
1444 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1445 (VOID *) &LoadfilePtr->Private->CallbackProtocolPtr\r
1446 );\r
1447\r
4ba61e5e 1448 if (Status == EFI_SUCCESS) {\r
878ddf1f 1449 //\r
1450 // There is already a callback routine. Do nothing.\r
1451 //\r
1452 DEBUG ((EFI_D_WARN, "\nLoadFile() BC callback exists."));\r
4ba61e5e 1453 } else if (Status == EFI_UNSUPPORTED) {\r
878ddf1f 1454 //\r
1455 // No BaseCode Callback protocol found. Add our own.\r
1456 //\r
1457 Status = gBS->InstallProtocolInterface (\r
1458 &LoadfilePtr->Private->Handle,\r
1459 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1460 EFI_NATIVE_INTERFACE,\r
1461 &_bc_callback\r
1462 );\r
1463\r
1464 DEBUG ((EFI_D_WARN, "\nLoadFile() Callback install status == %xh", Status));\r
1465\r
1466 RemoveCallback = (BOOLEAN) (Status == EFI_SUCCESS);\r
1467\r
1468 if (LoadfilePtr->Private->EfiBc.Mode != NULL && LoadfilePtr->Private->EfiBc.Mode->Started) {\r
1469 NewMakeCallback = TRUE;\r
1470 LoadfilePtr->Private->EfiBc.SetParameters (\r
1471 &LoadfilePtr->Private->EfiBc,\r
1472 NULL,\r
1473 NULL,\r
1474 NULL,\r
1475 NULL,\r
1476 &NewMakeCallback\r
1477 );\r
1478 }\r
4ba61e5e 1479 } else {\r
878ddf1f 1480 DEBUG ((EFI_D_WARN, "\nLoadFile() Callback check status == %xh", Status));\r
1481 }\r
1482 //\r
1483 // Check for starting or for continuing after already getting\r
1484 // the file size.\r
1485 //\r
1486 if (LoadfilePtr->Private->FileSize == 0) {\r
1487 TmpBufSz = 0;\r
1488 Status = LoadfileStart (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
1489\r
1490 if (sizeof (UINTN) < sizeof (UINT64) && TmpBufSz > 0xFFFFFFFF) {\r
1491 *BufferSize = 0xFFFFFFFF;\r
1492 } else {\r
1493 *BufferSize = (UINTN) TmpBufSz;\r
1494 }\r
1495\r
1496 if (Status == EFI_BUFFER_TOO_SMALL) {\r
1497 //\r
1498 // This is done so loadfile will work even if the boot manager\r
1499 // did not make the first call with Buffer == NULL.\r
1500 //\r
1501 Buffer = NULL;\r
1502 }\r
1503 } else if (Buffer == NULL) {\r
1504 DEBUG ((EFI_D_WARN, "\nLoadfile() Get buffer size"));\r
1505\r
1506 //\r
1507 // Continuing from previous LoadFile request. Make sure there\r
1508 // is a buffer and that it is big enough.\r
1509 //\r
1510 *BufferSize = LoadfilePtr->Private->FileSize;\r
1511 Status = EFI_BUFFER_TOO_SMALL;\r
1512 } else {\r
1513 DEBUG ((EFI_D_WARN, "\nLoadFile() Download file"));\r
1514\r
1515 //\r
1516 // Everything looks good, try to download the file.\r
1517 //\r
1518 TmpBufSz = *BufferSize;\r
1519 Status = DownloadFile (LoadfilePtr->Private, &TmpBufSz, Buffer);\r
1520\r
1521 //\r
1522 // Next call to loadfile will start DHCP process again.\r
1523 //\r
1524 LoadfilePtr->Private->FileSize = 0;\r
1525 }\r
1526 //\r
1527 // If we added a callback protocol, now is the time to remove it.\r
1528 //\r
1529 if (RemoveCallback) {\r
1530 NewMakeCallback = FALSE;\r
1531 TempStatus = LoadfilePtr->Private->EfiBc.SetParameters (\r
1532 &LoadfilePtr->Private->EfiBc,\r
1533 NULL,\r
1534 NULL,\r
1535 NULL,\r
1536 NULL,\r
1537 &NewMakeCallback\r
1538 );\r
1539\r
1540 if (TempStatus == EFI_SUCCESS) {\r
1541 gBS->UninstallProtocolInterface (\r
1542 LoadfilePtr->Private->Handle,\r
1543 &gEfiPxeBaseCodeCallbackProtocolGuid,\r
1544 &_bc_callback\r
1545 );\r
1546 }\r
1547 }\r
1548 //\r
1549 // Restore display mode and attribute\r
1550 //\r
1551 if (OrigMode != 0) {\r
1552 gST->ConOut->SetMode (gST->ConOut, OrigMode);\r
1553 }\r
1554\r
1555 gST->ConOut->SetAttribute (gST->ConOut, OrigAttribute);\r
1556\r
1557 //\r
1558 // Unlock interface\r
1559 //\r
1560 EfiReleaseLock (&LoadfilePtr->Lock);\r
1561\r
1562 DEBUG ((EFI_D_WARN, "\nBC.Loadfile() Status == %xh\n", Status));\r
1563\r
4ba61e5e 1564 if (Status == EFI_SUCCESS) {\r
1565 /* 0 */\r
878ddf1f 1566 return EFI_SUCCESS;\r
4ba61e5e 1567 } else if (Status == EFI_BUFFER_TOO_SMALL) {\r
1568 /* 5 */\r
878ddf1f 1569 //\r
1570 // Error is only displayed when we are actually trying to\r
1571 // download the boot image.\r
1572 //\r
1573 if (Buffer == NULL) {\r
1574 return EFI_BUFFER_TOO_SMALL;\r
1575 }\r
878ddf1f 1576 AsciiPrint ("\nPXE-E05: Download buffer is smaller than requested file.\n");\r
4ba61e5e 1577 } else if (Status == EFI_DEVICE_ERROR) {\r
1578 /* 7 */\r
878ddf1f 1579 AsciiPrint ("\nPXE-E07: Network device error. Check network connection.\n");\r
4ba61e5e 1580 } else if (Status == EFI_OUT_OF_RESOURCES) {\r
1581 /* 9 */\r
878ddf1f 1582 AsciiPrint ("\nPXE-E09: Could not allocate I/O buffers.\n");\r
4ba61e5e 1583 } else if (Status == EFI_NO_MEDIA) {\r
1584 /* 12 */\r
878ddf1f 1585 AsciiPrint ("\nPXE-E12: Could not detect network connection. Check cable.\n");\r
4ba61e5e 1586 } else if (Status == EFI_NO_RESPONSE) {\r
1587 /* 16 */\r
878ddf1f 1588 AsciiPrint ("\nPXE-E16: Valid PXE offer not received.\n");\r
4ba61e5e 1589 } else if (Status == EFI_TIMEOUT) {\r
1590 /* 18 */\r
878ddf1f 1591 AsciiPrint ("\nPXE-E18: Timeout. Server did not respond.\n");\r
4ba61e5e 1592 } else if (Status == EFI_ABORTED) {\r
1593 /* 21 */\r
878ddf1f 1594 AsciiPrint ("\nPXE-E21: Remote boot cancelled.\n");\r
4ba61e5e 1595 } else if (Status == EFI_ICMP_ERROR) {\r
1596 /* 22 */\r
878ddf1f 1597 AsciiPrint ("\nPXE-E22: Client received ICMP error from server.\n");\r
1598\r
4ba61e5e 1599 if ((LoadfilePtr->Private->EfiBc.Mode != NULL) && LoadfilePtr->Private->EfiBc.Mode->IcmpErrorReceived) {\r
1600 AsciiPrint (\r
1601 "PXE-E98: Type: %xh Code: %xh ",\r
1602 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type,\r
1603 LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code\r
1604 );\r
878ddf1f 1605\r
4ba61e5e 1606 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Type) {\r
1607 case 0x03:\r
1608 switch (LoadfilePtr->Private->EfiBc.Mode->IcmpError.Code) {\r
1609 case 0x00: /* net unreachable */\r
1610 AsciiPrint ("Net unreachable");\r
1611 break;\r
878ddf1f 1612\r
4ba61e5e 1613 case 0x01: /* host unreachable */\r
1614 AsciiPrint ("Host unreachable");\r
1615 break;\r
878ddf1f 1616\r
4ba61e5e 1617 case 0x02: /* protocol unreachable */\r
1618 AsciiPrint ("Protocol unreachable");\r
1619 break;\r
878ddf1f 1620\r
4ba61e5e 1621 case 0x03: /* port unreachable */\r
1622 AsciiPrint ("Port unreachable");\r
1623 break;\r
878ddf1f 1624\r
4ba61e5e 1625 case 0x04: /* Fragmentation needed */\r
1626 AsciiPrint ("Fragmentation needed");\r
1627 break;\r
878ddf1f 1628\r
4ba61e5e 1629 case 0x05: /* Source route failed */\r
1630 AsciiPrint ("Source route failed");\r
1631 break;\r
1632 }\r
878ddf1f 1633\r
878ddf1f 1634 break;\r
1635 }\r
1636\r
4ba61e5e 1637 AsciiPrint ("\n");\r
878ddf1f 1638 }\r
4ba61e5e 1639 } else if (Status == EFI_TFTP_ERROR) {\r
1640 /* 23 */\r
878ddf1f 1641 AsciiPrint ("\nPXE-E23: Client received TFTP error from server.\n");\r
1642\r
4ba61e5e 1643 if ((LoadfilePtr->Private->EfiBc.Mode != NULL) && (LoadfilePtr->Private->EfiBc.Mode->TftpErrorReceived)) {\r
878ddf1f 1644 AsciiPrint (\r
1645 "PXE-E98: Code: %xh %a\n",\r
1646 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorCode,\r
1647 LoadfilePtr->Private->EfiBc.Mode->TftpError.ErrorString\r
1648 );\r
1649 }\r
4ba61e5e 1650 } else {\r
878ddf1f 1651 AsciiPrint ("\nPXE-E99: Unexpected network error: %xh\n", Status);\r
1652 }\r
1653\r
1654 LoadfilePtr->Private->EfiBc.Stop (&LoadfilePtr->Private->EfiBc);\r
1655\r
1656 return Status;\r
1657}\r