]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcDhcp.c
Removed one include path which doesn't exist
[mirror_edk2.git] / MdeModulePkg / Universal / Network / UefiPxeBcDxe / PxeBcDhcp.c
CommitLineData
dc361cc5 1/** @file\r
2\r
3Copyright (c) 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\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
e48e37fc 65 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));\r
dc361cc5 66 Header->OpCode = PXEBC_DHCP4_OPCODE_REQUEST;\r
67 Header->HwType = Mode.IfType;\r
68 Header->HwAddrLen = (UINT8) Mode.HwAddressSize;\r
e48e37fc 69 CopyMem (Header->ClientHwAddr, &Mode.CurrentAddress, Header->HwAddrLen);\r
dc361cc5 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
e48e37fc 93 CopyMem (&Dst->Dhcp4, &Src->Dhcp4, Src->Length);\r
dc361cc5 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
e48e37fc 122 CopyMem (&Mode->ProxyOffer, &Offer->Dhcp4, Offer->Length);\r
dc361cc5 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
e48e37fc 150 ZeroMem (CachedPacket->Dhcp4Option, sizeof (CachedPacket->Dhcp4Option));\r
151 ZeroMem (&CachedPacket->PxeVendorOption, sizeof (CachedPacket->PxeVendorOption));\r
dc361cc5 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
e48e37fc 172 (CompareMem (Option->Data, DEFAULT_CLASS_ID_DATA, 9) == 0)) {\r
dc361cc5 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 EFI_FIELD_OFFSET (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
dc361cc5 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
e48e37fc 286 CopyMem (\r
dc361cc5 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
e48e37fc 295 CopyMem (&ServerIp.Addr[0], &Offer->Dhcp4.Header.ServerAddr, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 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
e48e37fc 330 CopyMem (&Private->PxeBc.Mode->ProxyOffer, &Reply->Dhcp4, Reply->Length);\r
dc361cc5 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 (Options[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL)) {\r
406 //\r
407 // The selected offer to finish the D.O.R.A. is a DHCP only offer and\r
408 // bootfile name is not provided in this offer, we need try proxy offers\r
409 // to get the bootfile name or the discovery info\r
410 //\r
411 ProxyOfferIndex = Private->NumOffers;\r
412\r
413 if (Private->SortOffers) {\r
414 //\r
415 // Choose proxy offer from the type we stored during DHCP offer selection\r
416 //\r
417 ASSERT (Private->ProxyIndex[Private->ProxyOfferType] > 0);\r
418\r
419 if (Private->ProxyOfferType == DHCP4_PACKET_TYPE_BINL) {\r
420 //\r
421 // We buffer all received BINL proxy offers, try them all one by one\r
422 //\r
423 if (!PxeBcTryBinlProxy (Private, &ProxyOfferIndex)) {\r
424 Status = EFI_NO_RESPONSE;\r
425 }\r
426 } else {\r
427 //\r
428 // For other types, only one proxy offer is buffered.\r
429 //\r
430 ProxyOfferIndex = Private->ProxyIndex[Private->ProxyOfferType] - 1;\r
431 }\r
432 } else {\r
433 //\r
434 // Choose proxy offer in the received order.\r
435 //\r
436 Status = EFI_NO_RESPONSE;\r
437\r
438 for (Index = 0; Index < Private->NumOffers; Index++) {\r
439\r
440 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
441 if (!IS_PROXY_DHCP_OFFER (Offer)) {\r
442 //\r
443 // Skip non proxy dhcp offers.\r
444 //\r
445 continue;\r
446 }\r
447\r
448 if (Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_BINL) {\r
449 //\r
450 // Try BINL\r
451 //\r
452 if (!PxeBcTryBinl (Private, Index)) {\r
453 //\r
454 // Failed, skip to the next offer\r
455 //\r
456 continue;\r
457 }\r
458 }\r
459\r
460 Status = EFI_SUCCESS;\r
461 break;\r
462 }\r
463 }\r
464\r
465 if (!EFI_ERROR (Status) && (Private->ProxyOfferType != DHCP4_PACKET_TYPE_BINL)) {\r
466 //\r
467 // Copy the proxy offer to Mode and set the flag\r
468 //\r
469 PxeBcCopyProxyOffer (Private, ProxyOfferIndex);\r
470 }\r
471 }\r
472\r
473 if (!EFI_ERROR (Status)) {\r
474 //\r
475 // Everything is OK, set the flag and copy the DHCP packets.\r
476 //\r
477 Mode = Private->PxeBc.Mode;\r
478 Offer = &SelectedOffer->Packet.Offer;\r
479\r
480 //\r
481 // The discover packet is already copied, just set flag here.\r
482 //\r
483 Mode->DhcpDiscoverValid = TRUE;\r
484\r
485 Ack = &Private->Dhcp4Ack.Packet.Ack;\r
486 if (SelectedOffer->OfferType == DHCP4_PACKET_TYPE_BOOTP) {\r
487 //\r
488 // Other type of ACK is already cached. Bootp is special that we should\r
489 // use the bootp reply as the ACK and put it into the DHCP_ONLY buffer.\r
490 //\r
491 PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Offer);\r
492 }\r
493\r
494 PxeBcParseCachedDhcpPacket (&Private->Dhcp4Ack);\r
495\r
496 Mode->DhcpAckReceived = TRUE;\r
497\r
498 //\r
499 // Copy the dhcp ack.\r
500 //\r
e48e37fc 501 CopyMem (&Mode->DhcpAck, &Ack->Dhcp4, Ack->Length);\r
dc361cc5 502 }\r
503\r
504 return Status;\r
505}\r
506\r
507\r
508/**\r
509 GC_NOTO: Add function description\r
510\r
511 @param Private GC_NOTO: add argument description\r
512 @param RcvdOffer GC_NOTO: add argument description\r
513\r
514 @return GC_NOTO: add return values\r
515\r
516**/\r
517VOID\r
518PxeBcCacheDhcpOffer (\r
519 IN PXEBC_PRIVATE_DATA *Private,\r
520 IN EFI_DHCP4_PACKET *RcvdOffer\r
521 )\r
522{\r
523 PXEBC_CACHED_DHCP4_PACKET *CachedOffer;\r
524 EFI_DHCP4_PACKET *Offer;\r
525 UINT8 OfferType;\r
526\r
527 CachedOffer = &Private->Dhcp4Offers[Private->NumOffers];\r
528 Offer = &CachedOffer->Packet.Offer;\r
529\r
530 //\r
531 // Cache the orignal dhcp packet\r
532 //\r
533 PxeBcCopyEfiDhcp4Packet (Offer, RcvdOffer);\r
534\r
535 //\r
536 // Parse and validate the options (including dhcp option and vendor option)\r
537 //\r
538 if (!PxeBcParseCachedDhcpPacket (CachedOffer)) {\r
539 return ;\r
540 }\r
541\r
542 OfferType = CachedOffer->OfferType;\r
543\r
544 if (OfferType == DHCP4_PACKET_TYPE_BOOTP) {\r
545\r
546 if (Private->BootpIndex != 0) {\r
547 //\r
548 // Only cache the first bootp offer, discard others.\r
549 //\r
550 return ;\r
551 } else {\r
552 //\r
553 // Take as a dhcp only offer, but record index specifically.\r
554 //\r
555 Private->BootpIndex = Private->NumOffers + 1;\r
556 }\r
557 } else {\r
558\r
559 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
560 //\r
561 // It's a proxy dhcp offer with no your address, including pxe10, wfm11a or binl offer.\r
562 //\r
563 if (OfferType == DHCP4_PACKET_TYPE_BINL) {\r
564 //\r
565 // Cache all binl offers.\r
566 //\r
567 Private->BinlIndex[Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]] = Private->NumOffers;\r
568 Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL]++;\r
569 } else if (Private->ProxyIndex[OfferType] != 0) {\r
570 //\r
571 // Only cache the first pxe10/wfm11a offers each, discard the others.\r
572 //\r
573 return ;\r
574 } else {\r
575 //\r
576 // Record index of the proxy dhcp offer with type other than binl.\r
577 //\r
578 Private->ProxyIndex[OfferType] = Private->NumOffers + 1;\r
579 }\r
580 } else {\r
581 //\r
582 // It's a dhcp offer with your address.\r
583 //\r
584 Private->OfferIndex[OfferType][Private->ServerCount[OfferType]] = Private->NumOffers;\r
585 Private->ServerCount[OfferType]++;\r
586 }\r
587 }\r
588\r
589 //\r
590 // Count the accepted offers.\r
591 //\r
592 Private->NumOffers++;\r
593}\r
594\r
595\r
596/**\r
597 GC_NOTO: Add function description\r
598\r
599 @param Private GC_NOTO: add argument description\r
600\r
601 @return GC_NOTO: add return values\r
602\r
603**/\r
604VOID\r
605PxeBcSelectOffer (\r
606 IN PXEBC_PRIVATE_DATA *Private\r
607 )\r
608{\r
609 UINT32 Index;\r
610 UINT32 OfferIndex;\r
611 EFI_DHCP4_PACKET *Offer;\r
612 BOOLEAN GotProxyOffer;\r
613\r
614 Private->SelectedOffer = 0;\r
615\r
616 if (Private->SortOffers) {\r
617 //\r
618 // Select offer according to the priority\r
619 //\r
620 if (Private->ServerCount[DHCP4_PACKET_TYPE_PXE10] > 0) {\r
621 //\r
622 // DHCP with PXE10\r
623 //\r
624 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_PXE10][0] + 1;\r
625\r
626 } else if (Private->ServerCount[DHCP4_PACKET_TYPE_WFM11A] > 0) {\r
627 //\r
628 // DHCP with WfM\r
629 //\r
630 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_WFM11A][0] + 1;\r
631\r
632 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_PXE10] > 0) &&\r
633 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
634 ) {\r
635 //\r
636 // DHCP only and proxy DHCP with PXE10\r
637 //\r
638 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
639 Private->ProxyOfferType = DHCP4_PACKET_TYPE_PXE10;\r
640\r
641 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_WFM11A] > 0) &&\r
642 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
643 ) {\r
644 //\r
645 // DHCP only and proxy DHCP with WfM\r
646 //\r
647 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
648 Private->ProxyOfferType = DHCP4_PACKET_TYPE_WFM11A;\r
649\r
650 } else if (Private->ServerCount[DHCP4_PACKET_TYPE_BINL] > 0) {\r
651 //\r
652 // DHCP with BINL\r
653 //\r
654 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_BINL][0] + 1;\r
655\r
656 } else if ((Private->ProxyIndex[DHCP4_PACKET_TYPE_BINL] > 0) &&\r
657 (Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY] > 0)\r
658 ) {\r
659 //\r
660 // DHCP only and proxy DHCP with BINL\r
661 //\r
662 Private->SelectedOffer = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][0] + 1;\r
663 Private->ProxyOfferType = DHCP4_PACKET_TYPE_BINL;\r
664\r
665 } else {\r
666 //\r
667 // Try offers with bootfile\r
668 //\r
669 for (Index = 0; Index < Private->ServerCount[DHCP4_PACKET_TYPE_DHCP_ONLY]; Index++) {\r
670 //\r
671 // Select the first DHCP only offer with bootfile\r
672 //\r
673 OfferIndex = Private->OfferIndex[DHCP4_PACKET_TYPE_DHCP_ONLY][Index];\r
674 if (Private->Dhcp4Offers[OfferIndex].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] != NULL) {\r
675 Private->SelectedOffer = OfferIndex + 1;\r
676 break;\r
677 }\r
678 }\r
679\r
680 if (Private->SelectedOffer == 0) {\r
681 //\r
682 // Select the Bootp reply with bootfile if any\r
683 //\r
684 Private->SelectedOffer = Private->BootpIndex;\r
685 }\r
686 }\r
687 } else {\r
688 //\r
689 // Try the offers in the received order.\r
690 //\r
691 GotProxyOffer = FALSE;\r
692 for (Index = 0; Index < DHCP4_PACKET_TYPE_MAX; Index++) {\r
693\r
694 GotProxyOffer = (BOOLEAN) (Private->ProxyIndex[Index] > 0);\r
695 if (GotProxyOffer) {\r
696 break;\r
697 }\r
698 }\r
699\r
700 for (Index = 0; Index < Private->NumOffers; Index++) {\r
701\r
702 Offer = &Private->Dhcp4Offers[Index].Packet.Offer;\r
703\r
704 if (IS_PROXY_DHCP_OFFER (Offer)) {\r
705 //\r
706 // Skip proxy offers\r
707 //\r
708 continue;\r
709 }\r
710\r
711 if ((Private->Dhcp4Offers[Index].OfferType == DHCP4_PACKET_TYPE_DHCP_ONLY) &&\r
712 ((!GotProxyOffer) && (Private->Dhcp4Offers[Index].Dhcp4Option[PXEBC_DHCP4_TAG_INDEX_BOOTFILE] == NULL))) {\r
713 //\r
714 // DHCP only offer but no proxy offer received and no bootfile option in this offer\r
715 //\r
716 continue;\r
717 }\r
718\r
719 Private->SelectedOffer = Index + 1;\r
720 break;\r
721 }\r
722 }\r
723}\r
724\r
725\r
726/**\r
727 GC_NOTO: Add function description\r
728\r
729 @param This GC_NOTO: add argument description\r
730 @param Context GC_NOTO: add argument description\r
731 @param CurrentState GC_NOTO: add argument description\r
732 @param Dhcp4Event GC_NOTO: add argument description\r
733 @param Packet GC_NOTO: add argument description\r
734 @param NewPacket GC_NOTO: add argument description\r
735\r
736 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
737 @retval EFI_ABORTED GC_NOTO: Add description for return value\r
738\r
739**/\r
740EFI_STATUS\r
741PxeBcDhcpCallBack (\r
742 IN EFI_DHCP4_PROTOCOL * This,\r
743 IN VOID *Context,\r
744 IN EFI_DHCP4_STATE CurrentState,\r
745 IN EFI_DHCP4_EVENT Dhcp4Event,\r
746 IN EFI_DHCP4_PACKET * Packet OPTIONAL,\r
747 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
748 )\r
749{\r
750 PXEBC_PRIVATE_DATA *Private;\r
751 EFI_PXE_BASE_CODE_MODE *Mode;\r
752 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;\r
753 EFI_DHCP4_PACKET_OPTION *MaxMsgSize;\r
754 UINT16 Value;\r
755 EFI_STATUS Status;\r
756 BOOLEAN Received;\r
757\r
758 if ((Dhcp4Event != Dhcp4RcvdOffer) &&\r
759 (Dhcp4Event != Dhcp4SelectOffer) &&\r
760 (Dhcp4Event != Dhcp4SendDiscover) &&\r
761 (Dhcp4Event != Dhcp4RcvdAck)) {\r
762 return EFI_SUCCESS;\r
763 }\r
764\r
765 Private = (PXEBC_PRIVATE_DATA *) Context;\r
766 Mode = Private->PxeBc.Mode;\r
767 Callback = Private->PxeBcCallback;\r
768\r
769 //\r
770 // Override the Maximum DHCP Message Size.\r
771 //\r
772 MaxMsgSize = PxeBcParseExtendOptions (\r
773 Packet->Dhcp4.Option,\r
774 GET_OPTION_BUFFER_LEN (Packet),\r
775 PXEBC_DHCP4_TAG_MAXMSG\r
776 );\r
777 if (MaxMsgSize != NULL) {\r
778 Value = HTONS (PXEBC_DHCP4_MAX_PACKET_SIZE);\r
e48e37fc 779 CopyMem (MaxMsgSize->Data, &Value, sizeof (Value));\r
dc361cc5 780 }\r
781\r
782 if ((Dhcp4Event != Dhcp4SelectOffer) && (Callback != NULL)) {\r
783 Received = (BOOLEAN) ((Dhcp4Event == Dhcp4RcvdOffer) || (Dhcp4Event == Dhcp4RcvdAck));\r
784 Status = Callback->Callback (\r
785 Callback,\r
786 Private->Function,\r
787 Received,\r
788 Packet->Length,\r
789 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp4\r
790 );\r
791 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {\r
792 return EFI_ABORTED;\r
793 }\r
794 }\r
795\r
796 Status = EFI_SUCCESS;\r
797\r
798 switch (Dhcp4Event) {\r
799\r
800 case Dhcp4SendDiscover:\r
801 //\r
802 // Cache the dhcp discover packet, of which some information will be used later.\r
803 //\r
e48e37fc 804 CopyMem (Mode->DhcpDiscover.Raw, &Packet->Dhcp4, Packet->Length);\r
dc361cc5 805\r
806 break;\r
807\r
808 case Dhcp4RcvdOffer:\r
809 Status = EFI_NOT_READY;\r
810 if (Private->NumOffers < PXEBC_MAX_OFFER_NUM) {\r
811 //\r
812 // Cache the dhcp offers in Private->Dhcp4Offers[]\r
813 //\r
814 PxeBcCacheDhcpOffer (Private, Packet);\r
815 }\r
816\r
817 break;\r
818\r
819 case Dhcp4SelectOffer:\r
820 //\r
821 // Select an offer, if succeeded, Private->SelectedOffer points to\r
822 // the index of the selected one.\r
823 //\r
824 PxeBcSelectOffer (Private);\r
825\r
826 if (Private->SelectedOffer == 0) {\r
827 Status = EFI_ABORTED;\r
828 } else {\r
829 *NewPacket = &Private->Dhcp4Offers[Private->SelectedOffer - 1].Packet.Offer;\r
830 }\r
831\r
832 break;\r
833\r
834 case Dhcp4RcvdAck:\r
835 //\r
836 // Cache Ack\r
837 //\r
838 ASSERT (Private->SelectedOffer != 0);\r
839\r
840 PxeBcCopyEfiDhcp4Packet (&Private->Dhcp4Ack.Packet.Ack, Packet);\r
841 break;\r
12f3a142 842\r
843 default:\r
844 break;\r
dc361cc5 845 }\r
846\r
847 return Status;\r
848}\r
849\r
850\r
851/**\r
852 GC_NOTO: Add function description\r
853\r
854 @param Private GC_NOTO: add argument description\r
855 @param OptList GC_NOTO: add argument description\r
856 @param IsDhcpDiscover GC_NOTO: add argument description\r
857\r
858 @return GC_NOTO: add return values\r
859\r
860**/\r
861UINT32\r
862PxeBcBuildDhcpOptions (\r
863 IN PXEBC_PRIVATE_DATA *Private,\r
864 IN EFI_DHCP4_PACKET_OPTION **OptList,\r
865 IN BOOLEAN IsDhcpDiscover\r
866 )\r
867{\r
868 UINT32 Index;\r
869 PXEBC_DHCP4_OPTION_ENTRY OptEnt;\r
870 UINT16 Value;\r
871 CHAR8 *SystemSerialNumber;\r
872\r
873 Index = 0;\r
874 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Private->OptionBuffer;\r
875\r
876 if (!IsDhcpDiscover) {\r
877 //\r
878 // Append message type.\r
879 //\r
880 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MSG_TYPE;\r
881 OptList[Index]->Length = 1;\r
882 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;\r
883 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;\r
884 Index++;\r
885 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
886\r
887 //\r
888 // Append max message size.\r
889 //\r
890 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MAXMSG;\r
891 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);\r
892 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;\r
893 Value = NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE);\r
e48e37fc 894 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));\r
dc361cc5 895 Index++;\r
896 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
897 }\r
898 //\r
899 // Parameter request list option.\r
900 //\r
901 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_PARA_LIST;\r
902 OptList[Index]->Length = 35;\r
903 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
904 OptEnt.Para->ParaList[0] = PXEBC_DHCP4_TAG_NETMASK;\r
905 OptEnt.Para->ParaList[1] = PXEBC_DHCP4_TAG_TIME_OFFSET;\r
906 OptEnt.Para->ParaList[2] = PXEBC_DHCP4_TAG_ROUTER;\r
907 OptEnt.Para->ParaList[3] = PXEBC_DHCP4_TAG_TIME_SERVER;\r
908 OptEnt.Para->ParaList[4] = PXEBC_DHCP4_TAG_NAME_SERVER;\r
909 OptEnt.Para->ParaList[5] = PXEBC_DHCP4_TAG_DNS_SERVER;\r
910 OptEnt.Para->ParaList[6] = PXEBC_DHCP4_TAG_HOSTNAME;\r
911 OptEnt.Para->ParaList[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN;\r
912 OptEnt.Para->ParaList[8] = PXEBC_DHCP4_TAG_DOMAINNAME;\r
913 OptEnt.Para->ParaList[9] = PXEBC_DHCP4_TAG_ROOTPATH;\r
914 OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH;\r
915 OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU;\r
916 OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL;\r
917 OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST;\r
918 OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN;\r
919 OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER;\r
920 OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER;\r
921 OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR;\r
922 OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP;\r
923 OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE;\r
924 OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID;\r
925 OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1;\r
926 OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2;\r
927 OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID;\r
928 OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP;\r
929 OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE;\r
930 OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID;\r
931 OptEnt.Para->ParaList[27] = 0x80;\r
932 OptEnt.Para->ParaList[28] = 0x81;\r
933 OptEnt.Para->ParaList[29] = 0x82;\r
934 OptEnt.Para->ParaList[30] = 0x83;\r
935 OptEnt.Para->ParaList[31] = 0x84;\r
936 OptEnt.Para->ParaList[32] = 0x85;\r
937 OptEnt.Para->ParaList[33] = 0x86;\r
938 OptEnt.Para->ParaList[34] = 0x87;\r
939 Index++;\r
940 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
941\r
942 //\r
943 // Append UUID/Guid-based client identifier option\r
944 //\r
945 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UUID;\r
946 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_UUID);\r
947 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;\r
948 OptEnt.Uuid->Type = 0;\r
949 Index++;\r
950 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
951\r
952 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID *) OptEnt.Uuid->Guid, &SystemSerialNumber))) {\r
953 //\r
954 // GUID not yet set - send all 0xff's to show programable (via SetVariable)\r
955 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);\r
956 // GUID not yet set - send all 0's to show not programable\r
957 //\r
958 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
959 }\r
960\r
961 //\r
962 // Append client network device interface option\r
963 //\r
964 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UNDI;\r
965 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_UNDI);\r
966 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
967 OptEnt.Undi->Type = Private->Nii->Type;\r
968 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
969 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
970\r
971 Index++;\r
972 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
973\r
974 //\r
975 // Append client system architecture option\r
976 //\r
977 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_ARCH;\r
978 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_ARCH);\r
979 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
980 Value = HTONS (SYS_ARCH);\r
e48e37fc 981 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
dc361cc5 982 Index++;\r
983 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
984\r
985 //\r
986 // Append client system architecture option\r
987 //\r
988 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_CLASS_ID;\r
989 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_CLID);\r
990 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
e48e37fc 991 CopyMem (OptEnt.Clid, DEFAULT_CLASS_ID_DATA, sizeof (PXEBC_DHCP4_OPTION_CLID));\r
dc361cc5 992 CvtNum (SYS_ARCH, OptEnt.Clid->ArchitectureType, sizeof (OptEnt.Clid->ArchitectureType));\r
e48e37fc 993 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
dc361cc5 994 CvtNum (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
995 CvtNum (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
996 Index++;\r
997\r
998 return Index;\r
999}\r
1000\r
1001\r
1002/**\r
1003 GC_NOTO: Add function description\r
1004\r
1005 @param Private GC_NOTO: add argument description\r
1006 @param Type GC_NOTO: add argument description\r
1007 @param Layer GC_NOTO: add argument description\r
1008 @param UseBis GC_NOTO: add argument description\r
1009 @param DestIp GC_NOTO: add argument description\r
1010 @param IpCount GC_NOTO: add argument description\r
1011 @param SrvList GC_NOTO: add argument description\r
1012 @param IsDiscv GC_NOTO: add argument description\r
1013 @param Reply GC_NOTO: add argument description\r
1014\r
1015 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value\r
1016\r
1017**/\r
1018EFI_STATUS\r
1019PxeBcDiscvBootService (\r
1020 IN PXEBC_PRIVATE_DATA * Private,\r
1021 IN UINT16 Type,\r
1022 IN UINT16 *Layer,\r
1023 IN BOOLEAN UseBis,\r
1024 IN EFI_IP_ADDRESS * DestIp,\r
1025 IN UINT16 IpCount,\r
1026 IN EFI_PXE_BASE_CODE_SRVLIST * SrvList,\r
1027 IN BOOLEAN IsDiscv,\r
1028 OUT EFI_DHCP4_PACKET * Reply OPTIONAL\r
1029 )\r
1030{\r
1031 EFI_PXE_BASE_CODE_UDP_PORT Sport;\r
1032 EFI_PXE_BASE_CODE_MODE *Mode;\r
1033 EFI_DHCP4_PROTOCOL *Dhcp4;\r
1034 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;\r
1035 BOOLEAN IsBCast;\r
1036 EFI_STATUS Status;\r
1037 UINT16 RepIndex;\r
1038 UINT16 SrvIndex;\r
1039 UINT16 TryIndex;\r
1040 EFI_DHCP4_LISTEN_POINT ListenPoint;\r
1041 EFI_DHCP4_PACKET *Response;\r
1042 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];\r
1043 UINT32 OptCount;\r
1044 EFI_DHCP4_PACKET_OPTION *PxeOpt;\r
1045 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;\r
1046 UINT8 VendorOptLen;\r
1047\r
1048 Mode = Private->PxeBc.Mode;\r
1049 Dhcp4 = Private->Dhcp4;\r
1050 Status = EFI_SUCCESS;\r
1051\r
1052 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));\r
1053\r
1054 if (DestIp == NULL) {\r
1055 Sport = PXEBC_DHCP4_S_PORT;\r
1056 IsBCast = TRUE;\r
1057 } else {\r
1058 Sport = PXEBC_BS_DISCOVER_PORT;\r
1059 IsBCast = FALSE;\r
1060 }\r
1061\r
1062 if (!UseBis && Layer != NULL) {\r
1063 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
1064 }\r
1065\r
1066 OptCount = PxeBcBuildDhcpOptions (Private, OptList, FALSE);\r
1067\r
1068 if (IsDiscv) {\r
1069 //\r
1070 // Add vendor option of PXE_BOOT_ITEM\r
1071 //\r
1072 VendorOptLen = (sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1;\r
e48e37fc 1073 OptList[OptCount] = AllocatePool (VendorOptLen);\r
dc361cc5 1074 if (OptList[OptCount] == NULL) {\r
1075 return EFI_OUT_OF_RESOURCES;\r
1076 }\r
1077\r
1078 OptList[OptCount]->OpCode = PXEBC_DHCP4_TAG_VENDOR;\r
1079 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2);\r
1080 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;\r
1081 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;\r
1082 PxeOpt->Length = sizeof (PXEBC_OPTION_BOOT_ITEM);\r
1083 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;\r
1084 PxeBootItem->Type = HTONS (Type);\r
1085 PxeBootItem->Layer = HTONS (*Layer);\r
1086 PxeOpt->Data[PxeOpt->Length] = PXEBC_DHCP4_TAG_EOP;\r
1087\r
1088 OptCount++;\r
1089 }\r
1090\r
1091 Status = Dhcp4->Build (Dhcp4, &Private->SeedPacket, 0, NULL, OptCount, OptList, &Token.Packet);\r
1092\r
1093 if (IsDiscv) {\r
e48e37fc 1094 gBS->FreePool (OptList[OptCount - 1]);\r
dc361cc5 1095 }\r
1096\r
1097 if (EFI_ERROR (Status)) {\r
1098 return Status;\r
1099 }\r
1100\r
1101 Token.Packet->Dhcp4.Header.Xid = NET_RANDOM (NetRandomInitSeed ());\r
1102 Token.Packet->Dhcp4.Header.Reserved = (UINT16) ((IsBCast) ? 0xf000 : 0x0);\r
e48e37fc 1103 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1104\r
1105 Token.RemotePort = Sport;\r
1106\r
1107 if (DestIp == NULL) {\r
e48e37fc 1108 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
dc361cc5 1109 } else {\r
e48e37fc 1110 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1111 }\r
1112\r
e48e37fc 1113 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1114\r
1115 if (!IsBCast) {\r
1116 Token.ListenPointCount = 1;\r
1117 Token.ListenPoints = &ListenPoint;\r
1118 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;\r
e48e37fc 1119 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));\r
1120 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));\r
dc361cc5 1121 }\r
1122 //\r
1123 // Send Pxe Discover\r
1124 //\r
1125 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {\r
1126\r
1127 Token.TimeoutValue = PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex;\r
1128\r
1129 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);\r
1130\r
1131 if (Token.Status != EFI_TIMEOUT) {\r
1132 break;\r
1133 }\r
1134 }\r
1135\r
1136 if (!EFI_ERROR (Status)) {\r
1137 //\r
1138 // Find Pxe Reply\r
1139 //\r
1140 RepIndex = 0;\r
1141 SrvIndex = 0;\r
1142 Response = Token.ResponseList;\r
1143\r
1144 while (RepIndex < Token.ResponseCount) {\r
1145\r
1146 while (SrvIndex < IpCount) {\r
1147\r
1148 if (SrvList[SrvIndex].AcceptAnyResponse) {\r
1149 break;\r
1150 }\r
1151\r
1152 if ((SrvList[SrvIndex].Type == Type) && EFI_IP4_EQUAL (&(Response->Dhcp4.Header.ServerAddr), &(Private->ServerIp))) {\r
1153 break;\r
1154 }\r
1155\r
1156 SrvIndex++;\r
1157 }\r
1158\r
1159 if ((IpCount != SrvIndex) || (IpCount == 0)) {\r
1160 break;\r
1161 }\r
1162\r
1163 SrvIndex = 0;\r
1164 RepIndex++;\r
1165\r
1166 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1167 }\r
1168\r
1169 if (RepIndex < Token.ResponseCount) {\r
1170\r
1171 if (Reply != NULL) {\r
1172 PxeBcCopyEfiDhcp4Packet (Reply, Response);\r
1173 }\r
1174\r
1175 if (IsDiscv) {\r
e48e37fc 1176 CopyMem (&(Mode->PxeDiscover), &(Token.Packet->Dhcp4), Token.Packet->Length);\r
dc361cc5 1177 Mode->PxeDiscoverValid = TRUE;\r
1178\r
e48e37fc 1179 CopyMem (Mode->PxeReply.Raw, &Response->Dhcp4, Response->Length);\r
dc361cc5 1180 Mode->PxeReplyReceived = TRUE;\r
1181 }\r
1182 } else {\r
1183 Status = EFI_NOT_FOUND;\r
1184 }\r
1185\r
1186 //\r
1187 // free the responselist\r
1188 //\r
e48e37fc 1189 gBS->FreePool (Token.ResponseList);\r
dc361cc5 1190 }\r
1191 //\r
1192 // Free the dhcp packet\r
1193 //\r
e48e37fc 1194 gBS->FreePool (Token.Packet);\r
dc361cc5 1195\r
1196 return Status;\r
1197}\r
1198\r
1199\r
1200/**\r
1201 GC_NOTO: Add function description\r
1202\r
1203 @param Buffer GC_NOTO: add argument description\r
1204 @param Length GC_NOTO: add argument description\r
1205 @param OptTag GC_NOTO: add argument description\r
1206\r
1207 @return GC_NOTO: add return values\r
1208\r
1209**/\r
1210EFI_DHCP4_PACKET_OPTION *\r
1211PxeBcParseExtendOptions (\r
1212 IN UINT8 *Buffer,\r
1213 IN UINT32 Length,\r
1214 IN UINT8 OptTag\r
1215 )\r
1216{\r
1217 EFI_DHCP4_PACKET_OPTION *Option;\r
1218 UINT32 Offset;\r
1219\r
1220 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
1221 Offset = 0;\r
1222\r
1223 while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) {\r
1224\r
1225 if (Option->OpCode == OptTag) {\r
1226\r
1227 return Option;\r
1228 }\r
1229\r
1230 if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
1231 Offset++;\r
1232 } else {\r
1233 Offset += Option->Length + 2;\r
1234 }\r
1235\r
1236 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);\r
1237 }\r
1238\r
1239 return NULL;\r
1240}\r
1241\r
1242\r
1243/**\r
1244 This function is to parse and check vendor options.\r
1245\r
1246 @param Dhcp4Option Pointer to dhcp options\r
1247 @param VendorOption Pointer to vendor options\r
1248\r
1249 @return TRUE : Valid vendor options\r
1250 @return FALSE : Invalid vendor options\r
1251\r
1252**/\r
1253BOOLEAN\r
1254PxeBcParseVendorOptions (\r
1255 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,\r
1256 IN PXEBC_VENDOR_OPTION *VendorOption\r
1257 )\r
1258{\r
1259 UINT32 *BitMap;\r
1260 UINT8 VendorOptionLen;\r
1261 EFI_DHCP4_PACKET_OPTION *PxeOption;\r
1262 UINT8 Offset;\r
1263\r
1264 BitMap = VendorOption->BitMap;\r
1265 VendorOptionLen = Dhcp4Option->Length;\r
1266 PxeOption = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];\r
1267 Offset = 0;\r
1268\r
1269 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) {\r
1270 //\r
1271 // Parse every Vendor Option and set its BitMap\r
1272 //\r
1273 switch (PxeOption->OpCode) {\r
1274\r
1275 case PXEBC_VENDOR_TAG_MTFTP_IP:\r
1276\r
e48e37fc 1277 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1278 break;\r
1279\r
1280 case PXEBC_VENDOR_TAG_MTFTP_CPORT:\r
1281\r
e48e37fc 1282 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));\r
dc361cc5 1283 break;\r
1284\r
1285 case PXEBC_VENDOR_TAG_MTFTP_SPORT:\r
1286\r
e48e37fc 1287 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));\r
dc361cc5 1288 break;\r
1289\r
1290 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:\r
1291\r
1292 VendorOption->MtftpTimeout = *PxeOption->Data;\r
1293 break;\r
1294\r
1295 case PXEBC_VENDOR_TAG_MTFTP_DELAY:\r
1296\r
1297 VendorOption->MtftpDelay = *PxeOption->Data;\r
1298 break;\r
1299\r
1300 case PXEBC_VENDOR_TAG_DISCOVER_CTRL:\r
1301\r
1302 VendorOption->DiscoverCtrl = *PxeOption->Data;\r
1303 break;\r
1304\r
1305 case PXEBC_VENDOR_TAG_DISCOVER_MCAST:\r
1306\r
e48e37fc 1307 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1308 break;\r
1309\r
1310 case PXEBC_VENDOR_TAG_BOOT_SERVERS:\r
1311\r
1312 VendorOption->BootSvrLen = PxeOption->Length;\r
1313 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;\r
1314 break;\r
1315\r
1316 case PXEBC_VENDOR_TAG_BOOT_MENU:\r
1317\r
1318 VendorOption->BootMenuLen = PxeOption->Length;\r
1319 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;\r
1320 break;\r
1321\r
1322 case PXEBC_VENDOR_TAG_MENU_PROMPT:\r
1323\r
1324 VendorOption->MenuPromptLen = PxeOption->Length;\r
1325 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *) PxeOption->Data;\r
1326 break;\r
1327\r
1328 case PXEBC_VENDOR_TAG_MCAST_ALLOC:\r
1329\r
e48e37fc 1330 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
1331 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));\r
1332 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));\r
dc361cc5 1333 break;\r
1334\r
1335 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:\r
1336\r
1337 VendorOption->CredTypeLen = PxeOption->Length;\r
1338 VendorOption->CredType = (UINT32 *) PxeOption->Data;\r
1339 break;\r
1340\r
1341 case PXEBC_VENDOR_TAG_BOOT_ITEM:\r
1342\r
e48e37fc 1343 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));\r
1344 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));\r
dc361cc5 1345 break;\r
1346 }\r
1347\r
1348 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);\r
1349\r
1350 if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
1351 Offset++;\r
1352 } else {\r
1353 Offset = (UINT8) (Offset + PxeOption->Length + 2);\r
1354 }\r
1355\r
1356 PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);\r
1357 }\r
1358\r
1359 //\r
1360 // FixMe, return falas if invalid of any vendor option\r
1361 //\r
1362\r
1363 return TRUE;\r
1364}\r
1365\r
1366\r
1367/**\r
1368 GC_NOTO: Add function description\r
1369\r
1370 @param Str GC_NOTO: add argument description\r
1371 @param Len GC_NOTO: add argument description\r
1372\r
1373 @return GC_NOTO: add return values\r
1374\r
1375**/\r
1376VOID\r
1377PxeBcDisplayBootItem (\r
1378 IN UINT8 *Str,\r
1379 IN UINT8 Len\r
1380 )\r
1381{\r
1382 UINT8 Tmp;\r
1383\r
1384 Len = (UINT8) MIN (70, Len);\r
1385 Tmp = Str[Len];\r
1386 Str[Len] = 0;\r
1387 AsciiPrint ("%a \n", Str);\r
1388 Str[Len] = Tmp;\r
1389}\r
1390\r
1391\r
1392/**\r
1393 GC_NOTO: Add function description\r
1394\r
1395 @param Private GC_NOTO: add argument description\r
1396\r
1397 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
1398 @retval EFI_TIMEOUT GC_NOTO: Add description for return value\r
1399\r
1400**/\r
1401EFI_STATUS\r
1402PxeBcSelectBootPrompt (\r
1403 IN PXEBC_PRIVATE_DATA *Private\r
1404 )\r
1405{\r
1406 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
1407 PXEBC_VENDOR_OPTION *VendorOpt;\r
1408 EFI_EVENT TimeoutEvent;\r
1409 EFI_EVENT DescendEvent;\r
1410 EFI_INPUT_KEY InputKey;\r
1411 EFI_STATUS Status;\r
1412 UINT8 Timeout;\r
1413 UINT8 *Prompt;\r
1414 UINT8 PromptLen;\r
1415 INT32 SecCol;\r
1416 INT32 SecRow;\r
1417\r
1418 TimeoutEvent = NULL;\r
1419 DescendEvent = NULL;\r
1420\r
1421 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1422\r
1423 Packet = &Private->ProxyOffer;\r
1424 } else {\r
1425\r
1426 Packet = &Private->Dhcp4Ack;\r
1427 }\r
1428\r
1429 if (Packet->OfferType != DHCP4_PACKET_TYPE_PXE10) {\r
1430 return EFI_NOT_FOUND;\r
1431 }\r
1432\r
1433 VendorOpt = &Packet->PxeVendorOption;\r
1434\r
1435 if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {\r
1436 return EFI_SUCCESS;\r
1437 }\r
1438\r
1439 Timeout = VendorOpt->MenuPrompt->Timeout;\r
1440 Prompt = VendorOpt->MenuPrompt->Prompt;\r
1441 PromptLen = (UINT8) (VendorOpt->MenuPromptLen - 1);\r
1442\r
1443 if (Timeout == 0) {\r
1444 return EFI_SUCCESS;\r
1445 }\r
1446\r
1447 if (Timeout == 255) {\r
1448 return EFI_TIMEOUT;\r
1449 }\r
1450\r
1451 Status = gBS->CreateEvent (\r
1452 EVT_TIMER,\r
1453 TPL_CALLBACK,\r
1454 NULL,\r
1455 NULL,\r
1456 &TimeoutEvent\r
1457 );\r
1458\r
1459 if (EFI_ERROR (Status)) {\r
1460 return Status;\r
1461 }\r
1462\r
1463 Status = gBS->SetTimer (\r
1464 TimeoutEvent,\r
1465 TimerRelative,\r
1466 Timeout * TICKS_PER_SECOND\r
1467 );\r
1468\r
1469 if (EFI_ERROR (Status)) {\r
1470 goto ON_EXIT;\r
1471 }\r
1472\r
1473 Status = gBS->CreateEvent (\r
1474 EVT_TIMER,\r
1475 TPL_CALLBACK,\r
1476 NULL,\r
1477 NULL,\r
1478 &DescendEvent\r
1479 );\r
1480\r
1481 if (EFI_ERROR (Status)) {\r
1482 goto ON_EXIT;\r
1483 }\r
1484\r
1485 Status = gBS->SetTimer (\r
1486 DescendEvent,\r
1487 TimerPeriodic,\r
1488 TICKS_PER_SECOND\r
1489 );\r
1490\r
1491 if (EFI_ERROR (Status)) {\r
1492 goto ON_EXIT;\r
1493 }\r
1494\r
1495 SecCol = gST->ConOut->Mode->CursorColumn;\r
1496 SecRow = gST->ConOut->Mode->CursorRow;\r
1497\r
1498 PxeBcDisplayBootItem (Prompt, PromptLen);\r
1499\r
1500 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1501 AsciiPrint ("(%d) ", Timeout--);\r
1502\r
1503 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
1504\r
1505 if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {\r
1506 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1507 AsciiPrint ("(%d) ", Timeout--);\r
1508 }\r
1509\r
1510 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1511\r
1512 gBS->Stall (10 * TICKS_PER_MS);\r
1513 continue;\r
1514 }\r
1515\r
1516 if (InputKey.ScanCode == 0) {\r
1517\r
1518 switch (InputKey.UnicodeChar) {\r
1519 case CTRL ('c'):\r
1520 Status = EFI_ABORTED;\r
1521 break;\r
1522\r
1523 case CTRL ('m'):\r
1524 case 'm':\r
1525 case 'M':\r
1526 Status = EFI_TIMEOUT;\r
1527 break;\r
1528\r
1529 default:\r
1530 continue;\r
1531 }\r
1532 } else {\r
1533\r
1534 switch (InputKey.ScanCode) {\r
1535 case SCAN_F8:\r
1536 Status = EFI_TIMEOUT;\r
1537 break;\r
1538\r
1539 case SCAN_ESC:\r
1540 Status = EFI_ABORTED;\r
1541 break;\r
1542\r
1543 default:\r
1544 continue;\r
1545 }\r
1546 }\r
1547\r
1548 break;\r
1549 }\r
1550\r
1551 gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1);\r
1552\r
1553ON_EXIT:\r
1554\r
1555 if (DescendEvent != NULL) {\r
1556 gBS->CloseEvent (DescendEvent);\r
1557 }\r
1558\r
1559 if (TimeoutEvent != NULL) {\r
1560 gBS->CloseEvent (TimeoutEvent);\r
1561 }\r
1562\r
1563 return Status;\r
1564}\r
1565\r
1566\r
1567/**\r
1568 GC_NOTO: Add function description\r
1569\r
1570 @param Private GC_NOTO: add argument description\r
1571 @param Type GC_NOTO: add argument description\r
1572\r
1573 @retval EFI_ABORTED GC_NOTO: Add description for return value\r
1574 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
1575\r
1576**/\r
1577EFI_STATUS\r
1578PxeBcSelectBootMenu (\r
1579 IN PXEBC_PRIVATE_DATA *Private,\r
1580 OUT UINT16 *Type,\r
1581 IN BOOLEAN UseDefaultItem\r
1582 )\r
1583{\r
1584 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
1585 PXEBC_VENDOR_OPTION *VendorOpt;\r
1586 EFI_INPUT_KEY InputKey;\r
1587 UINT8 MenuSize;\r
1588 UINT8 MenuNum;\r
1589 INT32 TopRow;\r
1590 UINT16 Select;\r
1591 UINT16 LastSelect;\r
1592 UINT8 Index;\r
1593 BOOLEAN Finish;\r
1594 CHAR8 Blank[70];\r
1595 PXEBC_BOOT_MENU_ENTRY *MenuItem;\r
1596 PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MAX_MENU_NUM];\r
1597\r
1598 Finish = FALSE;\r
1599 Select = 1;\r
1600 Index = 0;\r
1601 *Type = 0;\r
1602\r
1603 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1604\r
1605 Packet = &Private->ProxyOffer;\r
1606 } else {\r
1607\r
1608 Packet = &Private->Dhcp4Ack;\r
1609 }\r
1610\r
1611 ASSERT (Packet->OfferType == DHCP4_PACKET_TYPE_PXE10);\r
1612\r
1613 VendorOpt = &Packet->PxeVendorOption;\r
1614\r
1615 if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {\r
1616 return EFI_SUCCESS;\r
1617 }\r
1618\r
1619 SetMem (Blank, sizeof(Blank), ' ');\r
1620\r
1621 MenuSize = VendorOpt->BootMenuLen;\r
1622 MenuItem = VendorOpt->BootMenu;\r
1623\r
1624 while (MenuSize > 0) {\r
1625 MenuArray[Index] = MenuItem;\r
1626 MenuSize = (UINT8) (MenuSize - (MenuItem->DescLen + 3));\r
1627 MenuItem = (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + MenuItem->DescLen + 3);\r
1628 Index++;\r
1629 }\r
1630\r
1631 if (UseDefaultItem) {\r
1632 *Type = NTOHS (MenuArray[0]->Type);\r
1633 return EFI_SUCCESS;\r
1634 }\r
1635\r
1636 MenuNum = Index;\r
1637\r
1638 for (Index = 0; Index < MenuNum; Index++) {\r
1639 PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);\r
1640 }\r
1641\r
1642 TopRow = gST->ConOut->Mode->CursorRow - MenuNum;\r
1643\r
1644 do {\r
1645 //\r
1646 // highlight selected row\r
1647 //\r
1648 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
1649 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);\r
1650 Blank[MenuArray[Select]->DescLen] = 0;\r
1651 AsciiPrint ("%a\r", Blank);\r
1652 PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);\r
1653 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1654 LastSelect = Select;\r
1655\r
1656 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1657 gBS->Stall (10 * TICKS_PER_MS);\r
1658 }\r
1659\r
1660 if (!InputKey.ScanCode) {\r
1661 switch (InputKey.UnicodeChar) {\r
1662 case CTRL ('c'):\r
1663 InputKey.ScanCode = SCAN_ESC;\r
1664 break;\r
1665\r
1666 case CTRL ('j'): /* linefeed */\r
1667 case CTRL ('m'): /* return */\r
1668 Finish = TRUE;\r
1669 break;\r
1670\r
1671 case CTRL ('i'): /* tab */\r
1672 case ' ':\r
1673 case 'd':\r
1674 case 'D':\r
1675 InputKey.ScanCode = SCAN_DOWN;\r
1676 break;\r
1677\r
1678 case CTRL ('h'): /* backspace */\r
1679 case 'u':\r
1680 case 'U':\r
1681 InputKey.ScanCode = SCAN_UP;\r
1682 break;\r
1683\r
1684 default:\r
1685 InputKey.ScanCode = 0;\r
1686 }\r
1687 }\r
1688\r
1689 switch (InputKey.ScanCode) {\r
1690 case SCAN_LEFT:\r
1691 case SCAN_UP:\r
1692 if (Select) {\r
1693 --Select;\r
1694 }\r
1695\r
1696 break;\r
1697\r
1698 case SCAN_DOWN:\r
1699 case SCAN_RIGHT:\r
1700 if (++Select == MenuNum) {\r
1701 --Select;\r
1702 }\r
1703\r
1704 break;\r
1705\r
1706 case SCAN_PAGE_UP:\r
1707 case SCAN_HOME:\r
1708 Select = 0;\r
1709 break;\r
1710\r
1711 case SCAN_PAGE_DOWN:\r
1712 case SCAN_END:\r
1713 Select = (UINT16) (MenuNum - 1);\r
1714 break;\r
1715\r
1716 case SCAN_ESC:\r
1717 return EFI_ABORTED;\r
1718 }\r
1719\r
1720 /* unhighlight last selected row */\r
1721 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
1722 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);\r
1723 Blank[MenuArray[LastSelect]->DescLen] = 0;\r
1724 AsciiPrint ("%a\r", Blank);\r
1725 PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);\r
1726 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1727 } while (!Finish);\r
1728\r
1729 //\r
1730 // Swap the byte order\r
1731 //\r
1732 *Type = NTOHS (MenuArray[Select]->Type);\r
1733\r
1734 return EFI_SUCCESS;\r
1735}\r
1736\r