]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcDhcp.c
fix ecc
[mirror_edk2.git] / MdeModulePkg / Universal / Network / UefiPxeBcDxe / PxeBcDhcp.c
... / ...
CommitLineData
1/** @file\r
2\r
3Copyright (c) 2007 - 2008, 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\r
14 PxeBcDhcp.c\r
15\r
16Abstract:\r
17\r
18 Support for PxeBc dhcp functions\r
19\r
20\r
21**/\r
22\r
23\r
24#include "PxeBcImpl.h"\r
25\r
26//\r
27// This is a map from the interested DHCP4 option tags' index to the tag value.\r
28//\r
29UINT8 mInterestedDhcp4Tags[PXEBC_DHCP4_TAG_INDEX_MAX] = {\r
30 PXEBC_DHCP4_TAG_BOOTFILE_LEN,\r
31 PXEBC_DHCP4_TAG_VENDOR,\r
32 PXEBC_DHCP4_TAG_OVERLOAD,\r
33 PXEBC_DHCP4_TAG_MSG_TYPE,\r
34 PXEBC_DHCP4_TAG_SERVER_ID,\r
35 PXEBC_DHCP4_TAG_CLASS_ID,\r
36 PXEBC_DHCP4_TAG_BOOTFILE\r
37};\r
38\r
39\r
40/**\r
41 GC_NOTO: Add function description\r
42\r
43 @param Seed GC_NOTO: add argument description\r
44 @param Udp4 GC_NOTO: add argument description\r
45\r
46 @return GC_NOTO: add return values\r
47\r
48**/\r
49VOID\r
50PxeBcInitSeedPacket (\r
51 IN EFI_DHCP4_PACKET *Seed,\r
52 IN EFI_UDP4_PROTOCOL *Udp4\r
53 )\r
54{\r
55 EFI_SIMPLE_NETWORK_MODE Mode;\r
56 EFI_DHCP4_HEADER *Header;\r
57\r
58 Udp4->GetModeData (Udp4, NULL, NULL, NULL, &Mode);\r
59\r
60 Seed->Size = sizeof (EFI_DHCP4_PACKET);\r
61 Seed->Length = sizeof (Seed->Dhcp4);\r
62\r
63 Header = &Seed->Dhcp4.Header;\r
64\r
65 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));\r
66 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;\r
67 Header->HwType = Mode.IfType;\r
68 Header->HwAddrLen = (UINT8) Mode.HwAddressSize;\r
69 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);\r
70\r
71 Seed->Dhcp4.Magik = PXEBC_DHCP4_MAGIC;\r
72 Seed->Dhcp4.Option[0] = PXEBC_DHCP4_TAG_EOP;\r
73}\r
74\r
75\r
76/**\r
77 GC_NOTO: Add function description\r
78\r
79 @param Dst GC_NOTO: add argument description\r
80 @param Src GC_NOTO: add argument description\r
81\r
82 @return GC_NOTO: add return values\r
83\r
84**/\r
85VOID\r
86PxeBcCopyEfiDhcp4Packet (\r
87 IN EFI_DHCP4_PACKET *Dst,\r
88 IN EFI_DHCP4_PACKET *Src\r
89 )\r
90{\r
91 ASSERT (Dst->Size >= Src->Length);\r
92\r
93 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
94 Dst->Length = Src->Length;\r
95}\r
96\r
97\r
98/**\r
99 GC_NOTO: Add function description\r
100\r
101 @param Private GC_NOTO: add argument description\r
102 @param OfferIndex GC_NOTO: add argument description\r
103\r
104 @return GC_NOTO: add return values\r
105\r
106**/\r
107VOID\r
108PxeBcCopyProxyOffer (\r
109 IN PXEBC_PRIVATE_DATA *Private,\r
110 IN UINT32 OfferIndex\r
111 )\r
112{\r
113 EFI_PXE_BASE_CODE_MODE *Mode;\r
114 EFI_DHCP4_PACKET *Offer;\r
115\r
116 ASSERT (OfferIndex < Private->NumOffers);\r
117\r
118 Mode = Private->PxeBc.Mode;\r
119 Offer = &Private->Dhcp4Offers[OfferIndex].Packet.Offer;\r
120\r
121 PxeBcCopyEfiDhcp4Packet (&Private->ProxyOffer.Packet.Offer, Offer);\r
122 CopyMem (&Mode->ProxyOffer, &Offer->Dhcp4, Offer->Length);\r
123 Mode->ProxyOfferReceived = TRUE;\r
124\r
125 PxeBcParseCachedDhcpPacket (&Private->ProxyOffer);\r
126}\r
127\r
128\r
129/**\r
130 Parse the cached dhcp packet.\r
131\r
132 @param CachedPacket Pointer to cached dhcp packet\r
133\r
134 @return TRUE : Success to parse and validation\r
135 @return FALSE : Fail to parse or validation\r
136\r
137**/\r
138BOOLEAN\r
139PxeBcParseCachedDhcpPacket (\r
140 IN PXEBC_CACHED_DHCP4_PACKET *CachedPacket\r
141 )\r
142{\r
143 EFI_DHCP4_PACKET *Offer;\r
144 EFI_DHCP4_PACKET_OPTION **Options;\r
145 EFI_DHCP4_PACKET_OPTION *Option;\r
146 UINT8 OfferType;\r
147 UINTN Index;\r
148\r
149 CachedPacket->IsPxeOffer = FALSE;\r
150 ZeroMem (CachedPacket->Dhcp4Option, sizeof (CachedPacket->Dhcp4Option));\r
151 ZeroMem (&CachedPacket->PxeVendorOption, sizeof (CachedPacket->PxeVendorOption));\r
152\r
153 Offer = &CachedPacket->Packet.Offer;\r
154 Options = CachedPacket->Dhcp4Option;\r
155\r
156 //\r
157 // Parse interested dhcp options and store their pointers in CachedPacket->Dhcp4Option.\r
158 //\r
159 for (Index = 0; Index < PXEBC_DHCP4_TAG_INDEX_MAX; Index++) {\r
160 Options[Index] = PxeBcParseExtendOptions (\r
161 Offer->Dhcp4.Option,\r
162 GET_OPTION_BUFFER_LEN (Offer),\r
163 mInterestedDhcp4Tags[Index]\r
164 );\r
165 }\r
166\r
167 //\r
168 // Check whether is an offer with PXEClient or not.\r
169 //\r
170 Option = Options[PXEBC_DHCP4_TAG_INDEX_CLASS_ID];\r
171 if ((Option != NULL) && (Option->Length >= 9) &&\r
172 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {\r
173\r
174 CachedPacket->IsPxeOffer = TRUE;\r
175 }\r
176\r
177 //\r
178 // Parse pxe vendor options and store their content/pointers in CachedPacket->PxeVendorOption.\r
179 //\r
180 Option = Options[PXEBC_DHCP4_TAG_INDEX_VENDOR];\r
181 if (CachedPacket->IsPxeOffer && (Option != NULL)) {\r
182\r
183 if (!PxeBcParseVendorOptions (Option, &CachedPacket->PxeVendorOption)) {\r
184 return FALSE;\r
185 }\r
186 }\r
187\r
188 //\r
189 // Check whether bootfilename/serverhostname overloaded (See details in dhcp spec).\r
190 // If overloaded, parse this buffer as nested dhcp options, or just parse bootfilename/\r
191 // serverhostname option.\r
192 //\r
193 Option = Options[PXEBC_DHCP4_TAG_INDEX_OVERLOAD];\r
194 if ((Option != NULL) && (Option->Data[0] & PXEBC_DHCP4_OVERLOAD_FILE)) {\r
195\r
196 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = PxeBcParseExtendOptions (\r
197 (UINT8 *) Offer->Dhcp4.Header.BootFileName,\r
198 sizeof (Offer->Dhcp4.Header.BootFileName),\r
199 PXEBC_DHCP4_TAG_BOOTFILE\r
200 );\r
201\r
202 } else if ((Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL) &&\r
203 (Offer->Dhcp4.Header.BootFileName[0] != 0)) {\r
204 //\r
205 // If the bootfile is not present and bootfilename is present in dhcp packet, just parse it.\r
206 // And do not count dhcp option header, or else will destory the serverhostname.\r
207 //\r
208 Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] = (EFI_DHCP4_PACKET_OPTION *) (&Offer->Dhcp4.Header.BootFileName[0] -\r
209 OFFSET_OF (EFI_DHCP4_PACKET_OPTION, Data[0]));\r
210\r
211 }\r
212\r
213 //\r
214 // Determine offer type of the dhcp packet.\r
215 //\r
216 Option = Options[PXEBC_DHCP4_TAG_INDEX_MSG_TYPE];\r
217 if ((Option == NULL) || (Option->Data[0] == 0)) {\r
218 //\r
219 // It's a bootp offer\r
220 //\r
221 Option = CachedPacket->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE];\r
222 if (Option == NULL) {\r
223 //\r
224 // bootp offer without bootfilename, discard it.\r
225 //\r
226 return FALSE;\r
227 }\r
228\r
229 OfferType = DHCP4_PACKET_TYPE_BOOTP;\r
230\r
231 } else {\r
232\r
233 if (IS_VALID_DISCOVER_VENDOR_OPTION (CachedPacket->PxeVendorOption.BitMap)) {\r
234 //\r
235 // It's a pxe10 offer with PXEClient and discover vendor option.\r
236 //\r
237 OfferType = DHCP4_PACKET_TYPE_PXE10;\r
238 } else if (IS_VALID_MTFTP_VENDOR_OPTION (CachedPacket->PxeVendorOption.BitMap)) {\r
239 //\r
240 // It's a wfm11a offer with PXEClient and mtftp vendor option, and\r
241 // return false since mtftp not supported currently.\r
242 //\r
243 return FALSE;\r
244 } else {\r
245 //\r
246 // If the binl offer with only PXEClient.\r
247 //\r
248 OfferType = (UINT8) ((CachedPacket->IsPxeOffer) ? DHCP4_PACKET_TYPE_BINL : DHCP4_PACKET_TYPE_DHCP_ONLY);\r
249 }\r
250 }\r
251\r
252 CachedPacket->OfferType = OfferType;\r
253\r
254 return TRUE;\r
255}\r
256\r
257\r
258/**\r
259 GC_NOTO: Add function description\r
260\r
261 @param Private GC_NOTO: add argument description\r
262 @param Index GC_NOTO: add argument description\r
263\r
264 @return GC_NOTO: add return values\r
265\r
266**/\r
267BOOLEAN\r
268PxeBcTryBinl (\r
269 IN PXEBC_PRIVATE_DATA *Private,\r
270 IN UINT32 Index\r
271 )\r
272{\r
273 EFI_DHCP4_PACKET *Offer;\r
274 EFI_IP_ADDRESS ServerIp;\r
275 EFI_STATUS Status;\r
276 PXEBC_CACHED_DHCP4_PACKET *CachedPacket;\r
277 EFI_DHCP4_PACKET *Reply;\r
278\r
279 ASSERT (Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_BINL);\r
280\r
281 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
282 if (Offer->Dhcp4.Header.ServerAddr.Addr[0] == 0) {\r
283 //\r
284 // next server ip address is zero, use server id option instead.\r
285 //\r
286 CopyMem (\r
287 &ServerIp.Addr[0],\r
288 Private->Dhcp4Offers[Index].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_SERVER_ID]->Data,\r
289 sizeof (EFI_IPv4_ADDRESS)\r
290 );\r
291 } else {\r
292 //\r
293 // use next server ip address.\r
294 //\r
295 CopyMem (&ServerIp.Addr[0], &Offer->Dhcp4.Header.ServerAddr, sizeof (EFI_IPv4_ADDRESS));\r
296 }\r
297\r
298 CachedPacket = &Private->ProxyOffer;\r
299 Reply = &CachedPacket->Packet.Offer;\r
300\r
301 Status = PxeBcDiscvBootService (\r
302 Private,\r
303 0,\r
304 NULL,\r
305 FALSE,\r
306 &ServerIp,\r
307 0,\r
308 NULL,\r
309 FALSE,\r
310 Reply\r
311 );\r
312 if (EFI_ERROR (Status)) {\r
313 return FALSE;\r
314 }\r
315\r
316 if (!PxeBcParseCachedDhcpPacket (CachedPacket)) {\r
317 return FALSE;\r
318 }\r
319\r
320 if ((CachedPacket->OfferType != DHCP4_PACKET_TYPE_PXE10) &&\r
321 (CachedPacket->Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL)) {\r
322 //\r
323 // This BINL ack doesn't have discovery options set or bootfile name\r
324 // specified.\r
325 //\r
326 return FALSE;\r
327 }\r
328\r
329 Private->PxeBc.Mode->ProxyOfferReceived = TRUE;\r
330 CopyMem (&Private->PxeBc.Mode->ProxyOffer, &Reply->Dhcp4, Reply->Length);\r
331\r
332 return TRUE;\r
333}\r
334\r
335\r
336/**\r
337 GC_NOTO: Add function description\r
338\r
339 @param Private GC_NOTO: add argument description\r
340 @param OfferIndex GC_NOTO: add argument description\r
341\r
342 @return GC_NOTO: add return values\r
343\r
344**/\r
345BOOLEAN\r
346PxeBcTryBinlProxy (\r
347 IN PXEBC_PRIVATE_DATA *Private,\r
348 OUT UINT32 *OfferIndex\r
349 )\r
350{\r
351 UINT32 Index;\r
352\r
353 for (Index = 0; Index < Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]; Index++) {\r
354\r
355 *OfferIndex = Private->BinlIndex[Index];\r
356 //\r
357 // Try this BINL proxy offer\r
358 //\r
359 if (PxeBcTryBinl (Private, *OfferIndex)) {\r
360 return TRUE;\r
361 }\r
362 }\r
363\r
364 return FALSE;\r
365}\r
366\r
367\r
368/**\r
369 GC_NOTO: Add function description\r
370\r
371 @param Private GC_NOTO: add argument description\r
372\r
373 @return GC_NOTO: add return values\r
374\r
375**/\r
376EFI_STATUS\r
377PxeBcCheckSelectedOffer (\r
378 IN PXEBC_PRIVATE_DATA *Private\r
379 )\r
380{\r
381 PXEBC_CACHED_DHCP4_PACKET *SelectedOffer;\r
382 EFI_DHCP4_PACKET_OPTION **Options;\r
383 UINT32 Index;\r
384 EFI_DHCP4_PACKET *Offer;\r
385 UINT32 ProxyOfferIndex;\r
386 EFI_STATUS Status;\r
387 EFI_PXE_BASE_CODE_MODE *Mode;\r
388 EFI_DHCP4_PACKET *Ack;\r
389\r
390 ASSERT (Private->SelectedOffer != 0);\r
391\r
392 Status = EFI_SUCCESS;\r
393 SelectedOffer = &Private->Dhcp4Offers[Private->SelectedOffer - 1];\r
394 Options = SelectedOffer->Dhcp4Option;\r
395\r
396 if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_BINL) {\r
397 //\r
398 // The addresses are acquired from a BINL dhcp offer, try BINL to get\r
399 // the bootfile name\r
400 //\r
401 if (!PxeBcTryBinl (Private, Private->SelectedOffer - 1)) {\r
402 Status = EFI_NO_RESPONSE;\r
403 }\r
404 } else if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_DHCP_ONLY) {\r
405 //\r
406 // The selected offer to finish the D.O.R.A. is a DHCP only offer, we need \r
407 // try proxy offers if there are some, othewise the bootfile name must be \r
408 // set in this DHCP only offer.\r
409 //\r
410 if (Private->GotProxyOffer) {\r
411 //\r
412 // Get rid of the compiler warning.\r
413 //\r
414 ProxyOfferIndex = 0;\r
415 if (Private->SortOffers) {\r
416 //\r
417 // The offers are sorted before selecting, the proxy offer type must be\r
418 // already determined.\r
419 //\r
420 ASSERT (Private->ProxyIndex[Private->ProxyOfferType] > 0);\r
421\r
422 if (Private->ProxyOfferType == DHCP4_PACKET_TYPE_BINL) {\r
423 //\r
424 // We buffer all received BINL proxy offers, try them all one by one\r
425 //\r
426 if (!PxeBcTryBinlProxy (Private, &ProxyOfferIndex)) {\r
427 Status = EFI_NO_RESPONSE;\r
428 }\r
429 } else {\r
430 //\r
431 // For other types, only one proxy offer is buffered.\r
432 //\r
433 ProxyOfferIndex = Private->ProxyIndex[Private->ProxyOfferType] - 1;\r
434 }\r
435 } else {\r
436 //\r
437 // The proxy offer type is not determined, choose proxy offer in the \r
438 // received order.\r
439 //\r
440 Status = EFI_NO_RESPONSE;\r
441\r
442 for (Index = 0; Index < Private->NumOffers; Index++) {\r
443\r
444 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
445 if (!IS_PROXY_DHCP_OFFER (Offer)) {\r
446 //\r
447 // Skip non proxy dhcp offers.\r
448 //\r
449 continue;\r
450 }\r
451\r
452 if (Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_BINL) {\r
453 //\r
454 // Try BINL\r
455 //\r
456 if (!PxeBcTryBinl (Private, Index)) {\r
457 //\r
458 // Failed, skip to the next offer\r
459 //\r
460 continue;\r
461 }\r
462 }\r
463\r
464 Private->ProxyOfferType = Private->Dhcp4Offers[Index].OfferType;\r
465 ProxyOfferIndex = Index;\r
466 Status = EFI_SUCCESS;\r
467 break;\r
468 }\r
469 }\r
470\r
471 if (!EFI_ERROR (Status) && (Private->ProxyOfferType != DHCP4_PACKET_TYPE_BINL)) {\r
472 //\r
473 // Copy the proxy offer to Mode and set the flag\r
474 //\r
475 PxeBcCopyProxyOffer (Private, ProxyOfferIndex);\r
476 }\r
477 } else {\r
478 //\r
479 // No proxy offer is received, the bootfile name MUST be set.\r
480 //\r
481 ASSERT (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL);\r
482 }\r
483 }\r
484\r
485 if (!EFI_ERROR (Status)) {\r
486 //\r
487 // Everything is OK, set the flag and copy the DHCP packets.\r
488 //\r
489 Mode = Private->PxeBc.Mode;\r
490 Offer = &SelectedOffer->Packet.Offer;\r
491\r
492 //\r
493 // The discover packet is already copied, just set flag here.\r
494 //\r
495 Mode->DhcpDiscoverValid = TRUE;\r
496\r
497 Ack = &Private->Dhcp4Ack.Packet.Ack;\r
498 if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_BOOTP) {\r
499 //\r
500 // Other type of ACK is already cached. Bootp is special that we should\r
501 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.\r
502 //\r
503 PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Offer);\r
504 }\r
505\r
506 PxeBcParseCachedDhcpPacket (&Private->Dhcp4Ack);\r
507\r
508 Mode->DhcpAckReceived = TRUE;\r
509\r
510 //\r
511 // Copy the dhcp ack.\r
512 //\r
513 CopyMem (&Mode->DhcpAck, &Ack->Dhcp4, Ack->Length);\r
514 }\r
515\r
516 return Status;\r
517}\r
518\r
519\r
520/**\r
521 GC_NOTO: Add function description\r
522\r
523 @param Private GC_NOTO: add argument description\r
524 @param RcvdOffer GC_NOTO: add argument description\r
525\r
526 @return GC_NOTO: add return values\r
527\r
528**/\r
529VOID\r
530PxeBcCacheDhcpOffer (\r
531 IN PXEBC_PRIVATE_DATA *Private,\r
532 IN EFI_DHCP4_PACKET *RcvdOffer\r
533 )\r
534{\r
535 PXEBC_CACHED_DHCP4_PACKET *CachedOffer;\r
536 EFI_DHCP4_PACKET *Offer;\r
537 UINT8 OfferType;\r
538\r
539 CachedOffer = &Private->Dhcp4Offers[Private->NumOffers];\r
540 Offer = &CachedOffer->Packet.Offer;\r
541\r
542 //\r
543 // Cache the orignal dhcp packet\r
544 //\r
545 PxeBcCopyEfiDhcp4Packet (Offer, RcvdOffer);\r
546\r
547 //\r
548 // Parse and validate the options (including dhcp option and vendor option)\r
549 //\r
550 if (!PxeBcParseCachedDhcpPacket (CachedOffer)) {\r
551 return ;\r
552 }\r
553\r
554 OfferType = CachedOffer->OfferType;\r
555\r
556 if (OfferType == DHCP4_PACKET_TYPE_BOOTP) {\r
557\r
558 if (Private->BootpIndex != 0) {\r
559 //\r
560 // Only cache the first bootp offer, discard others.\r
561 //\r
562 return ;\r
563 } else {\r
564 //\r
565 // Take as a dhcp only offer, but record index specifically.\r
566 //\r
567 Private->BootpIndex = Private->NumOffers + 1;\r
568 }\r
569 } else {\r
570\r
571 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
572 //\r
573 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.\r
574 //\r
575 Private->GotProxyOffer = TRUE;\r
576\r
577 if (OfferType == DHCP4_PACKET_TYPE_BINL) {\r
578 //\r
579 // Cache all binl offers.\r
580 //\r
581 Private->BinlIndex[Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]] = Private->NumOffers;\r
582 Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]++;\r
583 } else if (Private->ProxyIndex[OfferType] != 0) {\r
584 //\r
585 // Only cache the first pxe10/wfm11a offers each, discard the others.\r
586 //\r
587 return ;\r
588 } else {\r
589 //\r
590 // Record index of the proxy dhcp offer with type other than binl.\r
591 //\r
592 Private->ProxyIndex[OfferType] = Private->NumOffers + 1;\r
593 }\r
594 } else {\r
595 //\r
596 // It's a dhcp offer with your address.\r
597 //\r
598 Private->OfferIndex[OfferType][Private->ServerCount[OfferType]] = Private->NumOffers;\r
599 Private->ServerCount[OfferType]++;\r
600 }\r
601 }\r
602\r
603 //\r
604 // Count the accepted offers.\r
605 //\r
606 Private->NumOffers++;\r
607}\r
608\r
609\r
610/**\r
611 GC_NOTO: Add function description\r
612\r
613 @param Private GC_NOTO: add argument description\r
614\r
615 @return GC_NOTO: add return values\r
616\r
617**/\r
618VOID\r
619PxeBcSelectOffer (\r
620 IN PXEBC_PRIVATE_DATA *Private\r
621 )\r
622{\r
623 UINT32 Index;\r
624 UINT32 OfferIndex;\r
625 EFI_DHCP4_PACKET *Offer;\r
626\r
627 Private->SelectedOffer = 0;\r
628\r
629 if (Private->SortOffers) {\r
630 //\r
631 // Select offer according to the priority\r
632 //\r
633 if (Private->ServerCount[DHCP4_PACKET_TYPE_PXE10] > 0) {\r
634 //\r
635 // DHCP with PXE10\r
636 //\r
637 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_PXE10][0] + 1;\r
638\r
639 } else if (Private->ServerCount[DHCP4_PACKET_TYPE_WFM11A] > 0) {\r
640 //\r
641 // DHCP with WfM\r
642 //\r
643 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_WFM11A][0] + 1;\r
644\r
645 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_PXE10] > 0) &&\r
646 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
647 ) {\r
648 //\r
649 // DHCP only and proxy DHCP with PXE10\r
650 //\r
651 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
652 Private->ProxyOfferType = DHCP4_PACKET_TYPE_PXE10;\r
653\r
654 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_WFM11A] > 0) &&\r
655 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
656 ) {\r
657 //\r
658 // DHCP only and proxy DHCP with WfM\r
659 //\r
660 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
661 Private->ProxyOfferType = DHCP4_PACKET_TYPE_WFM11A;\r
662\r
663 } else if (Private->ServerCount[DHCP4_PACKET_TYPE_BINL] > 0) {\r
664 //\r
665 // DHCP with BINL\r
666 //\r
667 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_BINL][0] + 1;\r
668\r
669 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL] > 0) &&\r
670 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
671 ) {\r
672 //\r
673 // DHCP only and proxy DHCP with BINL\r
674 //\r
675 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
676 Private->ProxyOfferType = DHCP4_PACKET_TYPE_BINL;\r
677\r
678 } else {\r
679 //\r
680 // Try offers with bootfile\r
681 //\r
682 for (Index = 0; Index < Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY]; Index++) {\r
683 //\r
684 // Select the first DHCP only offer with bootfile\r
685 //\r
686 OfferIndex = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][Index];\r
687 if (Private->Dhcp4Offers[OfferIndex].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
688 Private->SelectedOffer = OfferIndex + 1;\r
689 break;\r
690 }\r
691 }\r
692\r
693 if (Private->SelectedOffer == 0) {\r
694 //\r
695 // Select the Bootp reply with bootfile if any\r
696 //\r
697 Private->SelectedOffer = Private->BootpIndex;\r
698 }\r
699 }\r
700 } else {\r
701 //\r
702 // Try the offers in the received order.\r
703 //\r
704 for (Index = 0; Index < Private->NumOffers; Index++) {\r
705\r
706 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
707\r
708 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
709 //\r
710 // Skip proxy offers\r
711 //\r
712 continue;\r
713 }\r
714\r
715 if ((Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_DHCP_ONLY) &&\r
716 ((!Private->GotProxyOffer) && (Private->Dhcp4Offers[Index].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))) {\r
717 //\r
718 // DHCP only offer but no proxy offer received and no bootfile option in this offer\r
719 //\r
720 continue;\r
721 }\r
722\r
723 Private->SelectedOffer = Index + 1;\r
724 break;\r
725 }\r
726 }\r
727}\r
728\r
729\r
730/**\r
731 GC_NOTO: Add function description\r
732\r
733 @param This GC_NOTO: add argument description\r
734 @param Context GC_NOTO: add argument description\r
735 @param CurrentState GC_NOTO: add argument description\r
736 @param Dhcp4Event GC_NOTO: add argument description\r
737 @param Packet GC_NOTO: add argument description\r
738 @param NewPacket GC_NOTO: add argument description\r
739\r
740 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
741 @retval EFI_ABORTED GC_NOTO: Add description for return value\r
742\r
743**/\r
744EFI_STATUS\r
745PxeBcDhcpCallBack (\r
746 IN EFI_DHCP4_PROTOCOL * This,\r
747 IN VOID *Context,\r
748 IN EFI_DHCP4_STATE CurrentState,\r
749 IN EFI_DHCP4_EVENT Dhcp4Event,\r
750 IN EFI_DHCP4_PACKET * Packet OPTIONAL,\r
751 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
752 )\r
753{\r
754 PXEBC_PRIVATE_DATA *Private;\r
755 EFI_PXE_BASE_CODE_MODE *Mode;\r
756 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;\r
757 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
758 UINT16 Value;\r
759 EFI_STATUS Status;\r
760 BOOLEAN Received;\r
761 CHAR8 *SystemSerialNumber;\r
762 EFI_DHCP4_HEADER *DhcpHeader;\r
763\r
764 if ((Dhcp4Event != Dhcp4RcvdOffer) &&\r
765 (Dhcp4Event != Dhcp4SelectOffer) &&\r
766 (Dhcp4Event != Dhcp4SendDiscover) &&\r
767 (Dhcp4Event != Dhcp4RcvdAck) &&\r
768 (Dhcp4Event != Dhcp4SendRequest)) {\r
769 return EFI_SUCCESS;\r
770 }\r
771\r
772 Private = (PXEBC_PRIVATE_DATA *) Context;\r
773 Mode = Private->PxeBc.Mode;\r
774 Callback = Private->PxeBcCallback;\r
775\r
776 //\r
777 // Override the Maximum DHCP Message Size.\r
778 //\r
779 MaxMsgSize = PxeBcParseExtendOptions (\r
780 Packet->Dhcp4.Option,\r
781 GET_OPTION_BUFFER_LEN (Packet),\r
782 PXEBC_DHCP4_TAG_MAXMSG\r
783 );\r
784 if (MaxMsgSize != NULL) {\r
785 Value = HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE);\r
786 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
787 }\r
788\r
789 if ((Dhcp4Event != Dhcp4SelectOffer) && (Callback != NULL)) {\r
790 Received = (BOOLEAN) ((Dhcp4Event == Dhcp4RcvdOffer) || (Dhcp4Event == Dhcp4RcvdAck));\r
791 Status = Callback->Callback (\r
792 Callback,\r
793 Private->Function,\r
794 Received,\r
795 Packet->Length,\r
796 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4\r
797 );\r
798 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
799 return EFI_ABORTED;\r
800 }\r
801 }\r
802\r
803 Status = EFI_SUCCESS;\r
804\r
805 switch (Dhcp4Event) {\r
806\r
807 case Dhcp4SendDiscover:\r
808 case Dhcp4SendRequest:\r
809 if (Mode->SendGUID) {\r
810 //\r
811 // send the system GUID instead of the MAC address as the hardware address\r
812 // in the DHCP packet header.\r
813 //\r
814 DhcpHeader = &Packet->Dhcp4.Header;\r
815\r
816 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID *) DhcpHeader->ClientHwAddr, &SystemSerialNumber))) {\r
817 //\r
818 // GUID not yet set - send all 0xff's to show programable (via SetVariable)\r
819 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);\r
820 // GUID not yet set - send all 0's to show not programable\r
821 //\r
822 ZeroMem (DhcpHeader->ClientHwAddr, sizeof (EFI_GUID));\r
823 }\r
824\r
825 DhcpHeader->HwAddrLen = sizeof (EFI_GUID);\r
826 }\r
827\r
828 if (Dhcp4Event == Dhcp4SendDiscover) {\r
829 //\r
830 // Cache the dhcp discover packet, of which some information will be used later.\r
831 //\r
832 CopyMem (Mode->DhcpDiscover.Raw, &Packet->Dhcp4, Packet->Length);\r
833 }\r
834\r
835 break;\r
836\r
837 case Dhcp4RcvdOffer:\r
838 Status = EFI_NOT_READY;\r
839 if (Private->NumOffers < PXEBC_MAX_OFFER_NUM) {\r
840 //\r
841 // Cache the dhcp offers in Private->Dhcp4Offers[]\r
842 //\r
843 PxeBcCacheDhcpOffer (Private, Packet);\r
844 }\r
845\r
846 break;\r
847\r
848 case Dhcp4SelectOffer:\r
849 //\r
850 // Select an offer, if succeeded, Private->SelectedOffer points to\r
851 // the index of the selected one.\r
852 //\r
853 PxeBcSelectOffer (Private);\r
854\r
855 if (Private->SelectedOffer == 0) {\r
856 Status = EFI_ABORTED;\r
857 } else {\r
858 *NewPacket = &Private->Dhcp4Offers[Private->SelectedOffer - 1].Packet.Offer;\r
859 }\r
860\r
861 break;\r
862\r
863 case Dhcp4RcvdAck:\r
864 //\r
865 // Cache Ack\r
866 //\r
867 ASSERT (Private->SelectedOffer != 0);\r
868\r
869 PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Packet);\r
870 break;\r
871\r
872 default:\r
873 break;\r
874 }\r
875\r
876 return Status;\r
877}\r
878\r
879\r
880/**\r
881 GC_NOTO: Add function description\r
882\r
883 @param Private GC_NOTO: add argument description\r
884 @param OptList GC_NOTO: add argument description\r
885 @param IsDhcpDiscover GC_NOTO: add argument description\r
886\r
887 @return GC_NOTO: add return values\r
888\r
889**/\r
890UINT32\r
891PxeBcBuildDhcpOptions (\r
892 IN PXEBC_PRIVATE_DATA *Private,\r
893 IN EFI_DHCP4_PACKET_OPTION **OptList,\r
894 IN BOOLEAN IsDhcpDiscover\r
895 )\r
896{\r
897 UINT32 Index;\r
898 PXEBC_DHCP4_OPTION_ENTRY OptEnt;\r
899 UINT16 Value;\r
900 CHAR8 *SystemSerialNumber;\r
901\r
902 Index = 0;\r
903 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Private->OptionBuffer;\r
904\r
905 if (!IsDhcpDiscover) {\r
906 //\r
907 // Append message type.\r
908 //\r
909 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MSG_TYPE;\r
910 OptList[Index]->Length = 1;\r
911 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;\r
912 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;\r
913 Index++;\r
914 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
915\r
916 //\r
917 // Append max message size.\r
918 //\r
919 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MAXMSG;\r
920 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);\r
921 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;\r
922 Value = NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE);\r
923 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));\r
924 Index++;\r
925 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
926 }\r
927 //\r
928 // Parameter request list option.\r
929 //\r
930 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_PARA_LIST;\r
931 OptList[Index]->Length = 35;\r
932 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
933 OptEnt.Para->ParaList[0] = PXEBC_DHCP4_TAG_NETMASK;\r
934 OptEnt.Para->ParaList[1] = PXEBC_DHCP4_TAG_TIME_OFFSET;\r
935 OptEnt.Para->ParaList[2] = PXEBC_DHCP4_TAG_ROUTER;\r
936 OptEnt.Para->ParaList[3] = PXEBC_DHCP4_TAG_TIME_SERVER;\r
937 OptEnt.Para->ParaList[4] = PXEBC_DHCP4_TAG_NAME_SERVER;\r
938 OptEnt.Para->ParaList[5] = PXEBC_DHCP4_TAG_DNS_SERVER;\r
939 OptEnt.Para->ParaList[6] = PXEBC_DHCP4_TAG_HOSTNAME;\r
940 OptEnt.Para->ParaList[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN;\r
941 OptEnt.Para->ParaList[8] = PXEBC_DHCP4_TAG_DOMAINNAME;\r
942 OptEnt.Para->ParaList[9] = PXEBC_DHCP4_TAG_ROOTPATH;\r
943 OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH;\r
944 OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU;\r
945 OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL;\r
946 OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST;\r
947 OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN;\r
948 OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER;\r
949 OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER;\r
950 OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR;\r
951 OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP;\r
952 OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE;\r
953 OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID;\r
954 OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1;\r
955 OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2;\r
956 OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID;\r
957 OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP;\r
958 OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE;\r
959 OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID;\r
960 OptEnt.Para->ParaList[27] = 0x80;\r
961 OptEnt.Para->ParaList[28] = 0x81;\r
962 OptEnt.Para->ParaList[29] = 0x82;\r
963 OptEnt.Para->ParaList[30] = 0x83;\r
964 OptEnt.Para->ParaList[31] = 0x84;\r
965 OptEnt.Para->ParaList[32] = 0x85;\r
966 OptEnt.Para->ParaList[33] = 0x86;\r
967 OptEnt.Para->ParaList[34] = 0x87;\r
968 Index++;\r
969 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
970\r
971 //\r
972 // Append UUID/Guid-based client identifier option\r
973 //\r
974 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UUID;\r
975 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_UUID);\r
976 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;\r
977 OptEnt.Uuid->Type = 0;\r
978 Index++;\r
979 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
980\r
981 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID *) OptEnt.Uuid->Guid, &SystemSerialNumber))) {\r
982 //\r
983 // GUID not yet set - send all 0xff's to show programable (via SetVariable)\r
984 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);\r
985 // GUID not yet set - send all 0's to show not programable\r
986 //\r
987 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
988 }\r
989\r
990 //\r
991 // Append client network device interface option\r
992 //\r
993 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UNDI;\r
994 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_UNDI);\r
995 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
996 OptEnt.Undi->Type = Private->Nii->Type;\r
997 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
998 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
999\r
1000 Index++;\r
1001 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1002\r
1003 //\r
1004 // Append client system architecture option\r
1005 //\r
1006 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_ARCH;\r
1007 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_ARCH);\r
1008 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
1009 Value = HTONS (SYS_ARCH);\r
1010 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
1011 Index++;\r
1012 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
1013\r
1014 //\r
1015 // Append client system architecture option\r
1016 //\r
1017 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_CLASS_ID;\r
1018 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_CLID);\r
1019 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
1020 CopyMem (OptEnt.Clid, DEFAULT_CLASS_ID_DATA, sizeof (PXEBC_DHCP4_OPTION_CLID));\r
1021 CvtNum (SYS_ARCH, OptEnt.Clid->ArchitectureType, sizeof (OptEnt.Clid->ArchitectureType));\r
1022 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
1023 CvtNum (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
1024 CvtNum (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
1025 Index++;\r
1026\r
1027 return Index;\r
1028}\r
1029\r
1030\r
1031/**\r
1032 GC_NOTO: Add function description\r
1033\r
1034 @param Private GC_NOTO: add argument description\r
1035 @param Type GC_NOTO: add argument description\r
1036 @param Layer GC_NOTO: add argument description\r
1037 @param UseBis GC_NOTO: add argument description\r
1038 @param DestIp GC_NOTO: add argument description\r
1039 @param IpCount GC_NOTO: add argument description\r
1040 @param SrvList GC_NOTO: add argument description\r
1041 @param IsDiscv GC_NOTO: add argument description\r
1042 @param Reply GC_NOTO: add argument description\r
1043\r
1044 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value\r
1045\r
1046**/\r
1047EFI_STATUS\r
1048PxeBcDiscvBootService (\r
1049 IN PXEBC_PRIVATE_DATA * Private,\r
1050 IN UINT16 Type,\r
1051 IN UINT16 *Layer,\r
1052 IN BOOLEAN UseBis,\r
1053 IN EFI_IP_ADDRESS * DestIp,\r
1054 IN UINT16 IpCount,\r
1055 IN EFI_PXE_BASE_CODE_SRVLIST * SrvList,\r
1056 IN BOOLEAN IsDiscv,\r
1057 OUT EFI_DHCP4_PACKET * Reply OPTIONAL\r
1058 )\r
1059{\r
1060 EFI_PXE_BASE_CODE_UDP_PORT Sport;\r
1061 EFI_PXE_BASE_CODE_MODE *Mode;\r
1062 EFI_DHCP4_PROTOCOL *Dhcp4;\r
1063 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;\r
1064 BOOLEAN IsBCast;\r
1065 EFI_STATUS Status;\r
1066 UINT16 RepIndex;\r
1067 UINT16 SrvIndex;\r
1068 UINT16 TryIndex;\r
1069 EFI_DHCP4_LISTEN_POINT ListenPoint;\r
1070 EFI_DHCP4_PACKET *Response;\r
1071 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];\r
1072 UINT32 OptCount;\r
1073 EFI_DHCP4_PACKET_OPTION *PxeOpt;\r
1074 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;\r
1075 UINT8 VendorOptLen;\r
1076 CHAR8 *SystemSerialNumber;\r
1077 EFI_DHCP4_HEADER *DhcpHeader;\r
1078\r
1079\r
1080 Mode = Private->PxeBc.Mode;\r
1081 Dhcp4 = Private->Dhcp4;\r
1082 Status = EFI_SUCCESS;\r
1083\r
1084 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));\r
1085\r
1086 if (DestIp == NULL) {\r
1087 Sport = PXEBC_DHCP4_S_PORT;\r
1088 IsBCast = TRUE;\r
1089 } else {\r
1090 Sport = PXEBC_BS_DISCOVER_PORT;\r
1091 IsBCast = FALSE;\r
1092 }\r
1093\r
1094 if (!UseBis && Layer != NULL) {\r
1095 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
1096 }\r
1097\r
1098 OptCount = PxeBcBuildDhcpOptions (Private, OptList, FALSE);\r
1099\r
1100 if (IsDiscv) {\r
1101 //\r
1102 // Add vendor option of PXE_BOOT_ITEM\r
1103 //\r
1104 VendorOptLen = (sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1;\r
1105 OptList[OptCount] = AllocatePool (VendorOptLen);\r
1106 if (OptList[OptCount] == NULL) {\r
1107 return EFI_OUT_OF_RESOURCES;\r
1108 }\r
1109\r
1110 OptList[OptCount]->OpCode = PXEBC_DHCP4_TAG_VENDOR;\r
1111 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2);\r
1112 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;\r
1113 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;\r
1114 PxeOpt->Length = sizeof (PXEBC_OPTION_BOOT_ITEM);\r
1115 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;\r
1116 PxeBootItem->Type = HTONS (Type);\r
1117 PxeBootItem->Layer = HTONS (*Layer);\r
1118 PxeOpt->Data[PxeOpt->Length] = PXEBC_DHCP4_TAG_EOP;\r
1119\r
1120 OptCount++;\r
1121 }\r
1122\r
1123 Status = Dhcp4->Build (Dhcp4, &Private->SeedPacket, 0, NULL, OptCount, OptList, &Token.Packet);\r
1124\r
1125 if (IsDiscv) {\r
1126 gBS->FreePool (OptList[OptCount - 1]);\r
1127 }\r
1128\r
1129 if (EFI_ERROR (Status)) {\r
1130 return Status;\r
1131 }\r
1132\r
1133 DhcpHeader = &Token.Packet->Dhcp4.Header;\r
1134 if (Mode->SendGUID) {\r
1135 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID *) DhcpHeader->ClientHwAddr, &SystemSerialNumber))) {\r
1136 //\r
1137 // GUID not yet set - send all 0's to show not programable\r
1138 //\r
1139 ZeroMem (DhcpHeader->ClientHwAddr, sizeof (EFI_GUID));\r
1140 }\r
1141\r
1142 DhcpHeader->HwAddrLen = sizeof (EFI_GUID);\r
1143 }\r
1144\r
1145 Token.Packet->Dhcp4.Header.Xid = NET_RANDOM (NetRandomInitSeed ());\r
1146 Token.Packet->Dhcp4.Header.Reserved = (UINT16) ((IsBCast) ? 0xf000 : 0x0);\r
1147 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
1148\r
1149 Token.RemotePort = Sport;\r
1150\r
1151 if (DestIp == NULL) {\r
1152 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
1153 } else {\r
1154 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));\r
1155 }\r
1156\r
1157 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
1158\r
1159 if (!IsBCast) {\r
1160 Token.ListenPointCount = 1;\r
1161 Token.ListenPoints = &ListenPoint;\r
1162 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;\r
1163 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));\r
1164 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));\r
1165 }\r
1166 //\r
1167 // Send Pxe Discover\r
1168 //\r
1169 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {\r
1170\r
1171 Token.TimeoutValue = PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex;\r
1172\r
1173 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);\r
1174\r
1175 if (Token.Status != EFI_TIMEOUT) {\r
1176 break;\r
1177 }\r
1178 }\r
1179\r
1180 if (!EFI_ERROR (Status)) {\r
1181 //\r
1182 // Find Pxe Reply\r
1183 //\r
1184 RepIndex = 0;\r
1185 SrvIndex = 0;\r
1186 Response = Token.ResponseList;\r
1187\r
1188 while (RepIndex < Token.ResponseCount) {\r
1189\r
1190 while (SrvIndex < IpCount) {\r
1191\r
1192 if (SrvList[SrvIndex].AcceptAnyResponse) {\r
1193 break;\r
1194 }\r
1195\r
1196 if ((SrvList[SrvIndex].Type == Type) && EFI_IP4_EQUAL (&(Response->Dhcp4.Header.ServerAddr), &(Private->ServerIp))) {\r
1197 break;\r
1198 }\r
1199\r
1200 SrvIndex++;\r
1201 }\r
1202\r
1203 if ((IpCount != SrvIndex) || (IpCount == 0)) {\r
1204 break;\r
1205 }\r
1206\r
1207 SrvIndex = 0;\r
1208 RepIndex++;\r
1209\r
1210 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1211 }\r
1212\r
1213 if (RepIndex < Token.ResponseCount) {\r
1214\r
1215 if (Reply != NULL) {\r
1216 PxeBcCopyEfiDhcp4Packet (Reply, Response);\r
1217 }\r
1218\r
1219 if (IsDiscv) {\r
1220 CopyMem (&(Mode->PxeDiscover), &(Token.Packet->Dhcp4), Token.Packet->Length);\r
1221 Mode->PxeDiscoverValid = TRUE;\r
1222\r
1223 CopyMem (Mode->PxeReply.Raw, &Response->Dhcp4, Response->Length);\r
1224 Mode->PxeReplyReceived = TRUE;\r
1225 }\r
1226 } else {\r
1227 Status = EFI_NOT_FOUND;\r
1228 }\r
1229\r
1230 //\r
1231 // free the responselist\r
1232 //\r
1233 gBS->FreePool (Token.ResponseList);\r
1234 }\r
1235 //\r
1236 // Free the dhcp packet\r
1237 //\r
1238 gBS->FreePool (Token.Packet);\r
1239\r
1240 return Status;\r
1241}\r
1242\r
1243\r
1244/**\r
1245 GC_NOTO: Add function description\r
1246\r
1247 @param Buffer GC_NOTO: add argument description\r
1248 @param Length GC_NOTO: add argument description\r
1249 @param OptTag GC_NOTO: add argument description\r
1250\r
1251 @return GC_NOTO: add return values\r
1252\r
1253**/\r
1254EFI_DHCP4_PACKET_OPTION *\r
1255PxeBcParseExtendOptions (\r
1256 IN UINT8 *Buffer,\r
1257 IN UINT32 Length,\r
1258 IN UINT8 OptTag\r
1259 )\r
1260{\r
1261 EFI_DHCP4_PACKET_OPTION *Option;\r
1262 UINT32 Offset;\r
1263\r
1264 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
1265 Offset = 0;\r
1266\r
1267 while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) {\r
1268\r
1269 if (Option->OpCode == OptTag) {\r
1270\r
1271 return Option;\r
1272 }\r
1273\r
1274 if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
1275 Offset++;\r
1276 } else {\r
1277 Offset += Option->Length + 2;\r
1278 }\r
1279\r
1280 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);\r
1281 }\r
1282\r
1283 return NULL;\r
1284}\r
1285\r
1286\r
1287/**\r
1288 This function is to parse and check vendor options.\r
1289\r
1290 @param Dhcp4Option Pointer to dhcp options\r
1291 @param VendorOption Pointer to vendor options\r
1292\r
1293 @return TRUE : Valid vendor options\r
1294 @return FALSE : Invalid vendor options\r
1295\r
1296**/\r
1297BOOLEAN\r
1298PxeBcParseVendorOptions (\r
1299 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,\r
1300 IN PXEBC_VENDOR_OPTION *VendorOption\r
1301 )\r
1302{\r
1303 UINT32 *BitMap;\r
1304 UINT8 VendorOptionLen;\r
1305 EFI_DHCP4_PACKET_OPTION *PxeOption;\r
1306 UINT8 Offset;\r
1307\r
1308 BitMap = VendorOption->BitMap;\r
1309 VendorOptionLen = Dhcp4Option->Length;\r
1310 PxeOption = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];\r
1311 Offset = 0;\r
1312\r
1313 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) {\r
1314 //\r
1315 // Parse every Vendor Option and set its BitMap\r
1316 //\r
1317 switch (PxeOption->OpCode) {\r
1318\r
1319 case PXEBC_VENDOR_TAG_MTFTP_IP:\r
1320\r
1321 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
1322 break;\r
1323\r
1324 case PXEBC_VENDOR_TAG_MTFTP_CPORT:\r
1325\r
1326 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));\r
1327 break;\r
1328\r
1329 case PXEBC_VENDOR_TAG_MTFTP_SPORT:\r
1330\r
1331 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));\r
1332 break;\r
1333\r
1334 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:\r
1335\r
1336 VendorOption->MtftpTimeout = *PxeOption->Data;\r
1337 break;\r
1338\r
1339 case PXEBC_VENDOR_TAG_MTFTP_DELAY:\r
1340\r
1341 VendorOption->MtftpDelay = *PxeOption->Data;\r
1342 break;\r
1343\r
1344 case PXEBC_VENDOR_TAG_DISCOVER_CTRL:\r
1345\r
1346 VendorOption->DiscoverCtrl = *PxeOption->Data;\r
1347 break;\r
1348\r
1349 case PXEBC_VENDOR_TAG_DISCOVER_MCAST:\r
1350\r
1351 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
1352 break;\r
1353\r
1354 case PXEBC_VENDOR_TAG_BOOT_SERVERS:\r
1355\r
1356 VendorOption->BootSvrLen = PxeOption->Length;\r
1357 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;\r
1358 break;\r
1359\r
1360 case PXEBC_VENDOR_TAG_BOOT_MENU:\r
1361\r
1362 VendorOption->BootMenuLen = PxeOption->Length;\r
1363 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;\r
1364 break;\r
1365\r
1366 case PXEBC_VENDOR_TAG_MENU_PROMPT:\r
1367\r
1368 VendorOption->MenuPromptLen = PxeOption->Length;\r
1369 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *) PxeOption->Data;\r
1370 break;\r
1371\r
1372 case PXEBC_VENDOR_TAG_MCAST_ALLOC:\r
1373\r
1374 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
1375 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));\r
1376 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));\r
1377 break;\r
1378\r
1379 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:\r
1380\r
1381 VendorOption->CredTypeLen = PxeOption->Length;\r
1382 VendorOption->CredType = (UINT32 *) PxeOption->Data;\r
1383 break;\r
1384\r
1385 case PXEBC_VENDOR_TAG_BOOT_ITEM:\r
1386\r
1387 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));\r
1388 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));\r
1389 break;\r
1390 }\r
1391\r
1392 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);\r
1393\r
1394 if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
1395 Offset++;\r
1396 } else {\r
1397 Offset = (UINT8) (Offset + PxeOption->Length + 2);\r
1398 }\r
1399\r
1400 PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);\r
1401 }\r
1402\r
1403 //\r
1404 // FixMe, return falas if invalid of any vendor option\r
1405 //\r
1406\r
1407 return TRUE;\r
1408}\r
1409\r
1410\r
1411/**\r
1412 GC_NOTO: Add function description\r
1413\r
1414 @param Str GC_NOTO: add argument description\r
1415 @param Len GC_NOTO: add argument description\r
1416\r
1417 @return GC_NOTO: add return values\r
1418\r
1419**/\r
1420VOID\r
1421PxeBcDisplayBootItem (\r
1422 IN UINT8 *Str,\r
1423 IN UINT8 Len\r
1424 )\r
1425{\r
1426 UINT8 Tmp;\r
1427\r
1428 Len = (UINT8) MIN (70, Len);\r
1429 Tmp = Str[Len];\r
1430 Str[Len] = 0;\r
1431 AsciiPrint ("%a \n", Str);\r
1432 Str[Len] = Tmp;\r
1433}\r
1434\r
1435\r
1436/**\r
1437 GC_NOTO: Add function description\r
1438\r
1439 @param Private GC_NOTO: add argument description\r
1440\r
1441 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
1442 @retval EFI_TIMEOUT GC_NOTO: Add description for return value\r
1443\r
1444**/\r
1445EFI_STATUS\r
1446PxeBcSelectBootPrompt (\r
1447 IN PXEBC_PRIVATE_DATA *Private\r
1448 )\r
1449{\r
1450 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
1451 PXEBC_VENDOR_OPTION *VendorOpt;\r
1452 EFI_EVENT TimeoutEvent;\r
1453 EFI_EVENT DescendEvent;\r
1454 EFI_INPUT_KEY InputKey;\r
1455 EFI_STATUS Status;\r
1456 UINT8 Timeout;\r
1457 UINT8 *Prompt;\r
1458 UINT8 PromptLen;\r
1459 INT32 SecCol;\r
1460 INT32 SecRow;\r
1461\r
1462 TimeoutEvent = NULL;\r
1463 DescendEvent = NULL;\r
1464\r
1465 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1466\r
1467 Packet = &Private->ProxyOffer;\r
1468 } else {\r
1469\r
1470 Packet = &Private->Dhcp4Ack;\r
1471 }\r
1472\r
1473 if (Packet->OfferType != DHCP4_PACKET_TYPE_PXE10) {\r
1474 return EFI_NOT_FOUND;\r
1475 }\r
1476\r
1477 VendorOpt = &Packet->PxeVendorOption;\r
1478\r
1479 if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {\r
1480 return EFI_SUCCESS;\r
1481 }\r
1482\r
1483 Timeout = VendorOpt->MenuPrompt->Timeout;\r
1484 Prompt = VendorOpt->MenuPrompt->Prompt;\r
1485 PromptLen = (UINT8) (VendorOpt->MenuPromptLen - 1);\r
1486\r
1487 if (Timeout == 0) {\r
1488 return EFI_SUCCESS;\r
1489 }\r
1490\r
1491 if (Timeout == 255) {\r
1492 return EFI_TIMEOUT;\r
1493 }\r
1494\r
1495 Status = gBS->CreateEvent (\r
1496 EVT_TIMER,\r
1497 TPL_CALLBACK,\r
1498 NULL,\r
1499 NULL,\r
1500 &TimeoutEvent\r
1501 );\r
1502\r
1503 if (EFI_ERROR (Status)) {\r
1504 return Status;\r
1505 }\r
1506\r
1507 Status = gBS->SetTimer (\r
1508 TimeoutEvent,\r
1509 TimerRelative,\r
1510 Timeout * TICKS_PER_SECOND\r
1511 );\r
1512\r
1513 if (EFI_ERROR (Status)) {\r
1514 goto ON_EXIT;\r
1515 }\r
1516\r
1517 Status = gBS->CreateEvent (\r
1518 EVT_TIMER,\r
1519 TPL_CALLBACK,\r
1520 NULL,\r
1521 NULL,\r
1522 &DescendEvent\r
1523 );\r
1524\r
1525 if (EFI_ERROR (Status)) {\r
1526 goto ON_EXIT;\r
1527 }\r
1528\r
1529 Status = gBS->SetTimer (\r
1530 DescendEvent,\r
1531 TimerPeriodic,\r
1532 TICKS_PER_SECOND\r
1533 );\r
1534\r
1535 if (EFI_ERROR (Status)) {\r
1536 goto ON_EXIT;\r
1537 }\r
1538\r
1539 SecCol = gST->ConOut->Mode->CursorColumn;\r
1540 SecRow = gST->ConOut->Mode->CursorRow;\r
1541\r
1542 PxeBcDisplayBootItem (Prompt, PromptLen);\r
1543\r
1544 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1545 AsciiPrint ("(%d) ", Timeout--);\r
1546\r
1547 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
1548\r
1549 if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {\r
1550 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1551 AsciiPrint ("(%d) ", Timeout--);\r
1552 }\r
1553\r
1554 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1555\r
1556 gBS->Stall (10 * TICKS_PER_MS);\r
1557 continue;\r
1558 }\r
1559\r
1560 if (InputKey.ScanCode == 0) {\r
1561\r
1562 switch (InputKey.UnicodeChar) {\r
1563 case CTRL ('c'):\r
1564 Status = EFI_ABORTED;\r
1565 break;\r
1566\r
1567 case CTRL ('m'):\r
1568 case 'm':\r
1569 case 'M':\r
1570 Status = EFI_TIMEOUT;\r
1571 break;\r
1572\r
1573 default:\r
1574 continue;\r
1575 }\r
1576 } else {\r
1577\r
1578 switch (InputKey.ScanCode) {\r
1579 case SCAN_F8:\r
1580 Status = EFI_TIMEOUT;\r
1581 break;\r
1582\r
1583 case SCAN_ESC:\r
1584 Status = EFI_ABORTED;\r
1585 break;\r
1586\r
1587 default:\r
1588 continue;\r
1589 }\r
1590 }\r
1591\r
1592 break;\r
1593 }\r
1594\r
1595 gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1);\r
1596\r
1597ON_EXIT:\r
1598\r
1599 if (DescendEvent != NULL) {\r
1600 gBS->CloseEvent (DescendEvent);\r
1601 }\r
1602\r
1603 if (TimeoutEvent != NULL) {\r
1604 gBS->CloseEvent (TimeoutEvent);\r
1605 }\r
1606\r
1607 return Status;\r
1608}\r
1609\r
1610\r
1611/**\r
1612 GC_NOTO: Add function description\r
1613\r
1614 @param Private GC_NOTO: add argument description\r
1615 @param Type GC_NOTO: add argument description\r
1616\r
1617 @retval EFI_ABORTED GC_NOTO: Add description for return value\r
1618 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
1619\r
1620**/\r
1621EFI_STATUS\r
1622PxeBcSelectBootMenu (\r
1623 IN PXEBC_PRIVATE_DATA *Private,\r
1624 OUT UINT16 *Type,\r
1625 IN BOOLEAN UseDefaultItem\r
1626 )\r
1627{\r
1628 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
1629 PXEBC_VENDOR_OPTION *VendorOpt;\r
1630 EFI_INPUT_KEY InputKey;\r
1631 UINT8 MenuSize;\r
1632 UINT8 MenuNum;\r
1633 INT32 TopRow;\r
1634 UINT16 Select;\r
1635 UINT16 LastSelect;\r
1636 UINT8 Index;\r
1637 BOOLEAN Finish;\r
1638 CHAR8 Blank[70];\r
1639 PXEBC_BOOT_MENU_ENTRY *MenuItem;\r
1640 PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MAX_MENU_NUM];\r
1641\r
1642 Finish = FALSE;\r
1643 Select = 1;\r
1644 Index = 0;\r
1645 *Type = 0;\r
1646\r
1647 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1648\r
1649 Packet = &Private->ProxyOffer;\r
1650 } else {\r
1651\r
1652 Packet = &Private->Dhcp4Ack;\r
1653 }\r
1654\r
1655 ASSERT (Packet->OfferType == DHCP4_PACKET_TYPE_PXE10);\r
1656\r
1657 VendorOpt = &Packet->PxeVendorOption;\r
1658\r
1659 if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {\r
1660 return EFI_SUCCESS;\r
1661 }\r
1662\r
1663 SetMem (Blank, sizeof(Blank), ' ');\r
1664\r
1665 MenuSize = VendorOpt->BootMenuLen;\r
1666 MenuItem = VendorOpt->BootMenu;\r
1667\r
1668 while (MenuSize > 0) {\r
1669 MenuArray[Index] = MenuItem;\r
1670 MenuSize = (UINT8) (MenuSize - (MenuItem->DescLen + 3));\r
1671 MenuItem = (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + MenuItem->DescLen + 3);\r
1672 Index++;\r
1673 }\r
1674\r
1675 if (UseDefaultItem) {\r
1676 CopyMem (Type, &MenuArray[0]->Type, sizeof (UINT16));\r
1677 *Type = NTOHS (*Type);\r
1678 return EFI_SUCCESS;\r
1679 }\r
1680\r
1681 MenuNum = Index;\r
1682\r
1683 for (Index = 0; Index < MenuNum; Index++) {\r
1684 PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);\r
1685 }\r
1686\r
1687 TopRow = gST->ConOut->Mode->CursorRow - MenuNum;\r
1688\r
1689 do {\r
1690 //\r
1691 // highlight selected row\r
1692 //\r
1693 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
1694 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);\r
1695 Blank[MenuArray[Select]->DescLen] = 0;\r
1696 AsciiPrint ("%a\r", Blank);\r
1697 PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);\r
1698 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1699 LastSelect = Select;\r
1700\r
1701 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1702 gBS->Stall (10 * TICKS_PER_MS);\r
1703 }\r
1704\r
1705 if (!InputKey.ScanCode) {\r
1706 switch (InputKey.UnicodeChar) {\r
1707 case CTRL ('c'):\r
1708 InputKey.ScanCode = SCAN_ESC;\r
1709 break;\r
1710\r
1711 case CTRL ('j'): /* linefeed */\r
1712 case CTRL ('m'): /* return */\r
1713 Finish = TRUE;\r
1714 break;\r
1715\r
1716 case CTRL ('i'): /* tab */\r
1717 case ' ':\r
1718 case 'd':\r
1719 case 'D':\r
1720 InputKey.ScanCode = SCAN_DOWN;\r
1721 break;\r
1722\r
1723 case CTRL ('h'): /* backspace */\r
1724 case 'u':\r
1725 case 'U':\r
1726 InputKey.ScanCode = SCAN_UP;\r
1727 break;\r
1728\r
1729 default:\r
1730 InputKey.ScanCode = 0;\r
1731 }\r
1732 }\r
1733\r
1734 switch (InputKey.ScanCode) {\r
1735 case SCAN_LEFT:\r
1736 case SCAN_UP:\r
1737 if (Select) {\r
1738 --Select;\r
1739 }\r
1740\r
1741 break;\r
1742\r
1743 case SCAN_DOWN:\r
1744 case SCAN_RIGHT:\r
1745 if (++Select == MenuNum) {\r
1746 --Select;\r
1747 }\r
1748\r
1749 break;\r
1750\r
1751 case SCAN_PAGE_UP:\r
1752 case SCAN_HOME:\r
1753 Select = 0;\r
1754 break;\r
1755\r
1756 case SCAN_PAGE_DOWN:\r
1757 case SCAN_END:\r
1758 Select = (UINT16) (MenuNum - 1);\r
1759 break;\r
1760\r
1761 case SCAN_ESC:\r
1762 return EFI_ABORTED;\r
1763 }\r
1764\r
1765 /* unhighlight last selected row */\r
1766 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
1767 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);\r
1768 Blank[MenuArray[LastSelect]->DescLen] = 0;\r
1769 AsciiPrint ("%a\r", Blank);\r
1770 PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);\r
1771 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1772 } while (!Finish);\r
1773\r
1774 //\r
1775 // Swap the byte order\r
1776 //\r
1777 CopyMem (Type, &MenuArray[Select]->Type, sizeof (UINT16));\r
1778 *Type = NTOHS (*Type);\r
1779\r
1780 return EFI_SUCCESS;\r
1781}\r
1782\r