]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/UefiPxeBcDxe/PxeBcDhcp.c
Use Mde library and definition instead of some native definitions in NetLib, to simpl...
[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
842 }\r
843\r
844 return Status;\r
845}\r
846\r
847\r
848/**\r
849 GC_NOTO: Add function description\r
850\r
851 @param Private GC_NOTO: add argument description\r
852 @param OptList GC_NOTO: add argument description\r
853 @param IsDhcpDiscover GC_NOTO: add argument description\r
854\r
855 @return GC_NOTO: add return values\r
856\r
857**/\r
858UINT32\r
859PxeBcBuildDhcpOptions (\r
860 IN PXEBC_PRIVATE_DATA *Private,\r
861 IN EFI_DHCP4_PACKET_OPTION **OptList,\r
862 IN BOOLEAN IsDhcpDiscover\r
863 )\r
864{\r
865 UINT32 Index;\r
866 PXEBC_DHCP4_OPTION_ENTRY OptEnt;\r
867 UINT16 Value;\r
868 CHAR8 *SystemSerialNumber;\r
869\r
870 Index = 0;\r
871 OptList[0] = (EFI_DHCP4_PACKET_OPTION *) Private->OptionBuffer;\r
872\r
873 if (!IsDhcpDiscover) {\r
874 //\r
875 // Append message type.\r
876 //\r
877 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MSG_TYPE;\r
878 OptList[Index]->Length = 1;\r
879 OptEnt.Mesg = (PXEBC_DHCP4_OPTION_MESG *) OptList[Index]->Data;\r
880 OptEnt.Mesg->Type = PXEBC_DHCP4_MSG_TYPE_REQUEST;\r
881 Index++;\r
882 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
883\r
884 //\r
885 // Append max message size.\r
886 //\r
887 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_MAXMSG;\r
888 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE);\r
889 OptEnt.MaxMesgSize = (PXEBC_DHCP4_OPTION_MAX_MESG_SIZE *) OptList[Index]->Data;\r
890 Value = NTOHS (PXEBC_DHCP4_MAX_PACKET_SIZE);\r
e48e37fc 891 CopyMem (&OptEnt.MaxMesgSize->Size, &Value, sizeof (UINT16));\r
dc361cc5 892 Index++;\r
893 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
894 }\r
895 //\r
896 // Parameter request list option.\r
897 //\r
898 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_PARA_LIST;\r
899 OptList[Index]->Length = 35;\r
900 OptEnt.Para = (PXEBC_DHCP4_OPTION_PARA *) OptList[Index]->Data;\r
901 OptEnt.Para->ParaList[0] = PXEBC_DHCP4_TAG_NETMASK;\r
902 OptEnt.Para->ParaList[1] = PXEBC_DHCP4_TAG_TIME_OFFSET;\r
903 OptEnt.Para->ParaList[2] = PXEBC_DHCP4_TAG_ROUTER;\r
904 OptEnt.Para->ParaList[3] = PXEBC_DHCP4_TAG_TIME_SERVER;\r
905 OptEnt.Para->ParaList[4] = PXEBC_DHCP4_TAG_NAME_SERVER;\r
906 OptEnt.Para->ParaList[5] = PXEBC_DHCP4_TAG_DNS_SERVER;\r
907 OptEnt.Para->ParaList[6] = PXEBC_DHCP4_TAG_HOSTNAME;\r
908 OptEnt.Para->ParaList[7] = PXEBC_DHCP4_TAG_BOOTFILE_LEN;\r
909 OptEnt.Para->ParaList[8] = PXEBC_DHCP4_TAG_DOMAINNAME;\r
910 OptEnt.Para->ParaList[9] = PXEBC_DHCP4_TAG_ROOTPATH;\r
911 OptEnt.Para->ParaList[10] = PXEBC_DHCP4_TAG_EXTEND_PATH;\r
912 OptEnt.Para->ParaList[11] = PXEBC_DHCP4_TAG_EMTU;\r
913 OptEnt.Para->ParaList[12] = PXEBC_DHCP4_TAG_TTL;\r
914 OptEnt.Para->ParaList[13] = PXEBC_DHCP4_TAG_BROADCAST;\r
915 OptEnt.Para->ParaList[14] = PXEBC_DHCP4_TAG_NIS_DOMAIN;\r
916 OptEnt.Para->ParaList[15] = PXEBC_DHCP4_TAG_NIS_SERVER;\r
917 OptEnt.Para->ParaList[16] = PXEBC_DHCP4_TAG_NTP_SERVER;\r
918 OptEnt.Para->ParaList[17] = PXEBC_DHCP4_TAG_VENDOR;\r
919 OptEnt.Para->ParaList[18] = PXEBC_DHCP4_TAG_REQUEST_IP;\r
920 OptEnt.Para->ParaList[19] = PXEBC_DHCP4_TAG_LEASE;\r
921 OptEnt.Para->ParaList[20] = PXEBC_DHCP4_TAG_SERVER_ID;\r
922 OptEnt.Para->ParaList[21] = PXEBC_DHCP4_TAG_T1;\r
923 OptEnt.Para->ParaList[22] = PXEBC_DHCP4_TAG_T2;\r
924 OptEnt.Para->ParaList[23] = PXEBC_DHCP4_TAG_CLASS_ID;\r
925 OptEnt.Para->ParaList[24] = PXEBC_DHCP4_TAG_TFTP;\r
926 OptEnt.Para->ParaList[25] = PXEBC_DHCP4_TAG_BOOTFILE;\r
927 OptEnt.Para->ParaList[26] = PXEBC_PXE_DHCP4_TAG_UUID;\r
928 OptEnt.Para->ParaList[27] = 0x80;\r
929 OptEnt.Para->ParaList[28] = 0x81;\r
930 OptEnt.Para->ParaList[29] = 0x82;\r
931 OptEnt.Para->ParaList[30] = 0x83;\r
932 OptEnt.Para->ParaList[31] = 0x84;\r
933 OptEnt.Para->ParaList[32] = 0x85;\r
934 OptEnt.Para->ParaList[33] = 0x86;\r
935 OptEnt.Para->ParaList[34] = 0x87;\r
936 Index++;\r
937 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
938\r
939 //\r
940 // Append UUID/Guid-based client identifier option\r
941 //\r
942 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UUID;\r
943 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_UUID);\r
944 OptEnt.Uuid = (PXEBC_DHCP4_OPTION_UUID *) OptList[Index]->Data;\r
945 OptEnt.Uuid->Type = 0;\r
946 Index++;\r
947 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
948\r
949 if (EFI_ERROR (GetSmbiosSystemGuidAndSerialNumber ((EFI_GUID *) OptEnt.Uuid->Guid, &SystemSerialNumber))) {\r
950 //\r
951 // GUID not yet set - send all 0xff's to show programable (via SetVariable)\r
952 // SetMem(DHCPV4_OPTIONS_BUFFER.DhcpPlatformId.Guid, sizeof(EFI_GUID), 0xff);\r
953 // GUID not yet set - send all 0's to show not programable\r
954 //\r
955 ZeroMem (OptEnt.Uuid->Guid, sizeof (EFI_GUID));\r
956 }\r
957\r
958 //\r
959 // Append client network device interface option\r
960 //\r
961 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_UNDI;\r
962 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_UNDI);\r
963 OptEnt.Undi = (PXEBC_DHCP4_OPTION_UNDI *) OptList[Index]->Data;\r
964 OptEnt.Undi->Type = Private->Nii->Type;\r
965 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;\r
966 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;\r
967\r
968 Index++;\r
969 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
970\r
971 //\r
972 // Append client system architecture option\r
973 //\r
974 OptList[Index]->OpCode = PXEBC_PXE_DHCP4_TAG_ARCH;\r
975 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_ARCH);\r
976 OptEnt.Arch = (PXEBC_DHCP4_OPTION_ARCH *) OptList[Index]->Data;\r
977 Value = HTONS (SYS_ARCH);\r
e48e37fc 978 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));\r
dc361cc5 979 Index++;\r
980 OptList[Index] = GET_NEXT_DHCP_OPTION (OptList[Index - 1]);\r
981\r
982 //\r
983 // Append client system architecture option\r
984 //\r
985 OptList[Index]->OpCode = PXEBC_DHCP4_TAG_CLASS_ID;\r
986 OptList[Index]->Length = sizeof (PXEBC_DHCP4_OPTION_CLID);\r
987 OptEnt.Clid = (PXEBC_DHCP4_OPTION_CLID *) OptList[Index]->Data;\r
e48e37fc 988 CopyMem (OptEnt.Clid, DEFAULT_CLASS_ID_DATA, sizeof (PXEBC_DHCP4_OPTION_CLID));\r
dc361cc5 989 CvtNum (SYS_ARCH, OptEnt.Clid->ArchitectureType, sizeof (OptEnt.Clid->ArchitectureType));\r
e48e37fc 990 CopyMem (OptEnt.Clid->InterfaceName, Private->Nii->StringId, sizeof (OptEnt.Clid->InterfaceName));\r
dc361cc5 991 CvtNum (Private->Nii->MajorVer, OptEnt.Clid->UndiMajor, sizeof (OptEnt.Clid->UndiMajor));\r
992 CvtNum (Private->Nii->MinorVer, OptEnt.Clid->UndiMinor, sizeof (OptEnt.Clid->UndiMinor));\r
993 Index++;\r
994\r
995 return Index;\r
996}\r
997\r
998\r
999/**\r
1000 GC_NOTO: Add function description\r
1001\r
1002 @param Private GC_NOTO: add argument description\r
1003 @param Type GC_NOTO: add argument description\r
1004 @param Layer GC_NOTO: add argument description\r
1005 @param UseBis GC_NOTO: add argument description\r
1006 @param DestIp GC_NOTO: add argument description\r
1007 @param IpCount GC_NOTO: add argument description\r
1008 @param SrvList GC_NOTO: add argument description\r
1009 @param IsDiscv GC_NOTO: add argument description\r
1010 @param Reply GC_NOTO: add argument description\r
1011\r
1012 @retval EFI_OUT_OF_RESOURCES GC_NOTO: Add description for return value\r
1013\r
1014**/\r
1015EFI_STATUS\r
1016PxeBcDiscvBootService (\r
1017 IN PXEBC_PRIVATE_DATA * Private,\r
1018 IN UINT16 Type,\r
1019 IN UINT16 *Layer,\r
1020 IN BOOLEAN UseBis,\r
1021 IN EFI_IP_ADDRESS * DestIp,\r
1022 IN UINT16 IpCount,\r
1023 IN EFI_PXE_BASE_CODE_SRVLIST * SrvList,\r
1024 IN BOOLEAN IsDiscv,\r
1025 OUT EFI_DHCP4_PACKET * Reply OPTIONAL\r
1026 )\r
1027{\r
1028 EFI_PXE_BASE_CODE_UDP_PORT Sport;\r
1029 EFI_PXE_BASE_CODE_MODE *Mode;\r
1030 EFI_DHCP4_PROTOCOL *Dhcp4;\r
1031 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;\r
1032 BOOLEAN IsBCast;\r
1033 EFI_STATUS Status;\r
1034 UINT16 RepIndex;\r
1035 UINT16 SrvIndex;\r
1036 UINT16 TryIndex;\r
1037 EFI_DHCP4_LISTEN_POINT ListenPoint;\r
1038 EFI_DHCP4_PACKET *Response;\r
1039 EFI_DHCP4_PACKET_OPTION *OptList[PXEBC_DHCP4_MAX_OPTION_NUM];\r
1040 UINT32 OptCount;\r
1041 EFI_DHCP4_PACKET_OPTION *PxeOpt;\r
1042 PXEBC_OPTION_BOOT_ITEM *PxeBootItem;\r
1043 UINT8 VendorOptLen;\r
1044\r
1045 Mode = Private->PxeBc.Mode;\r
1046 Dhcp4 = Private->Dhcp4;\r
1047 Status = EFI_SUCCESS;\r
1048\r
1049 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));\r
1050\r
1051 if (DestIp == NULL) {\r
1052 Sport = PXEBC_DHCP4_S_PORT;\r
1053 IsBCast = TRUE;\r
1054 } else {\r
1055 Sport = PXEBC_BS_DISCOVER_PORT;\r
1056 IsBCast = FALSE;\r
1057 }\r
1058\r
1059 if (!UseBis && Layer != NULL) {\r
1060 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;\r
1061 }\r
1062\r
1063 OptCount = PxeBcBuildDhcpOptions (Private, OptList, FALSE);\r
1064\r
1065 if (IsDiscv) {\r
1066 //\r
1067 // Add vendor option of PXE_BOOT_ITEM\r
1068 //\r
1069 VendorOptLen = (sizeof (EFI_DHCP4_PACKET_OPTION) - 1) * 2 + sizeof (PXEBC_OPTION_BOOT_ITEM) + 1;\r
e48e37fc 1070 OptList[OptCount] = AllocatePool (VendorOptLen);\r
dc361cc5 1071 if (OptList[OptCount] == NULL) {\r
1072 return EFI_OUT_OF_RESOURCES;\r
1073 }\r
1074\r
1075 OptList[OptCount]->OpCode = PXEBC_DHCP4_TAG_VENDOR;\r
1076 OptList[OptCount]->Length = (UINT8) (VendorOptLen - 2);\r
1077 PxeOpt = (EFI_DHCP4_PACKET_OPTION *) OptList[OptCount]->Data;\r
1078 PxeOpt->OpCode = PXEBC_VENDOR_TAG_BOOT_ITEM;\r
1079 PxeOpt->Length = sizeof (PXEBC_OPTION_BOOT_ITEM);\r
1080 PxeBootItem = (PXEBC_OPTION_BOOT_ITEM *) PxeOpt->Data;\r
1081 PxeBootItem->Type = HTONS (Type);\r
1082 PxeBootItem->Layer = HTONS (*Layer);\r
1083 PxeOpt->Data[PxeOpt->Length] = PXEBC_DHCP4_TAG_EOP;\r
1084\r
1085 OptCount++;\r
1086 }\r
1087\r
1088 Status = Dhcp4->Build (Dhcp4, &Private->SeedPacket, 0, NULL, OptCount, OptList, &Token.Packet);\r
1089\r
1090 if (IsDiscv) {\r
e48e37fc 1091 gBS->FreePool (OptList[OptCount - 1]);\r
dc361cc5 1092 }\r
1093\r
1094 if (EFI_ERROR (Status)) {\r
1095 return Status;\r
1096 }\r
1097\r
1098 Token.Packet->Dhcp4.Header.Xid = NET_RANDOM (NetRandomInitSeed ());\r
1099 Token.Packet->Dhcp4.Header.Reserved = (UINT16) ((IsBCast) ? 0xf000 : 0x0);\r
e48e37fc 1100 CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1101\r
1102 Token.RemotePort = Sport;\r
1103\r
1104 if (DestIp == NULL) {\r
e48e37fc 1105 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);\r
dc361cc5 1106 } else {\r
e48e37fc 1107 CopyMem (&Token.RemoteAddress, DestIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1108 }\r
1109\r
e48e37fc 1110 CopyMem (&Token.GatewayAddress, &Private->GatewayIp, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1111\r
1112 if (!IsBCast) {\r
1113 Token.ListenPointCount = 1;\r
1114 Token.ListenPoints = &ListenPoint;\r
1115 Token.ListenPoints[0].ListenPort = PXEBC_BS_DISCOVER_PORT;\r
e48e37fc 1116 CopyMem (&Token.ListenPoints[0].ListenAddress, &Private->StationIp, sizeof(EFI_IPv4_ADDRESS));\r
1117 CopyMem (&Token.ListenPoints[0].SubnetMask, &Private->SubnetMask, sizeof(EFI_IPv4_ADDRESS));\r
dc361cc5 1118 }\r
1119 //\r
1120 // Send Pxe Discover\r
1121 //\r
1122 for (TryIndex = 1; TryIndex <= PXEBC_BOOT_REQUEST_RETRIES; TryIndex++) {\r
1123\r
1124 Token.TimeoutValue = PXEBC_BOOT_REQUEST_TIMEOUT * TryIndex;\r
1125\r
1126 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);\r
1127\r
1128 if (Token.Status != EFI_TIMEOUT) {\r
1129 break;\r
1130 }\r
1131 }\r
1132\r
1133 if (!EFI_ERROR (Status)) {\r
1134 //\r
1135 // Find Pxe Reply\r
1136 //\r
1137 RepIndex = 0;\r
1138 SrvIndex = 0;\r
1139 Response = Token.ResponseList;\r
1140\r
1141 while (RepIndex < Token.ResponseCount) {\r
1142\r
1143 while (SrvIndex < IpCount) {\r
1144\r
1145 if (SrvList[SrvIndex].AcceptAnyResponse) {\r
1146 break;\r
1147 }\r
1148\r
1149 if ((SrvList[SrvIndex].Type == Type) && EFI_IP4_EQUAL (&(Response->Dhcp4.Header.ServerAddr), &(Private->ServerIp))) {\r
1150 break;\r
1151 }\r
1152\r
1153 SrvIndex++;\r
1154 }\r
1155\r
1156 if ((IpCount != SrvIndex) || (IpCount == 0)) {\r
1157 break;\r
1158 }\r
1159\r
1160 SrvIndex = 0;\r
1161 RepIndex++;\r
1162\r
1163 Response = (EFI_DHCP4_PACKET *) ((UINT8 *) Response + Response->Size);\r
1164 }\r
1165\r
1166 if (RepIndex < Token.ResponseCount) {\r
1167\r
1168 if (Reply != NULL) {\r
1169 PxeBcCopyEfiDhcp4Packet (Reply, Response);\r
1170 }\r
1171\r
1172 if (IsDiscv) {\r
e48e37fc 1173 CopyMem (&(Mode->PxeDiscover), &(Token.Packet->Dhcp4), Token.Packet->Length);\r
dc361cc5 1174 Mode->PxeDiscoverValid = TRUE;\r
1175\r
e48e37fc 1176 CopyMem (Mode->PxeReply.Raw, &Response->Dhcp4, Response->Length);\r
dc361cc5 1177 Mode->PxeReplyReceived = TRUE;\r
1178 }\r
1179 } else {\r
1180 Status = EFI_NOT_FOUND;\r
1181 }\r
1182\r
1183 //\r
1184 // free the responselist\r
1185 //\r
e48e37fc 1186 gBS->FreePool (Token.ResponseList);\r
dc361cc5 1187 }\r
1188 //\r
1189 // Free the dhcp packet\r
1190 //\r
e48e37fc 1191 gBS->FreePool (Token.Packet);\r
dc361cc5 1192\r
1193 return Status;\r
1194}\r
1195\r
1196\r
1197/**\r
1198 GC_NOTO: Add function description\r
1199\r
1200 @param Buffer GC_NOTO: add argument description\r
1201 @param Length GC_NOTO: add argument description\r
1202 @param OptTag GC_NOTO: add argument description\r
1203\r
1204 @return GC_NOTO: add return values\r
1205\r
1206**/\r
1207EFI_DHCP4_PACKET_OPTION *\r
1208PxeBcParseExtendOptions (\r
1209 IN UINT8 *Buffer,\r
1210 IN UINT32 Length,\r
1211 IN UINT8 OptTag\r
1212 )\r
1213{\r
1214 EFI_DHCP4_PACKET_OPTION *Option;\r
1215 UINT32 Offset;\r
1216\r
1217 Option = (EFI_DHCP4_PACKET_OPTION *) Buffer;\r
1218 Offset = 0;\r
1219\r
1220 while (Offset < Length && Option->OpCode != PXEBC_DHCP4_TAG_EOP) {\r
1221\r
1222 if (Option->OpCode == OptTag) {\r
1223\r
1224 return Option;\r
1225 }\r
1226\r
1227 if (Option->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
1228 Offset++;\r
1229 } else {\r
1230 Offset += Option->Length + 2;\r
1231 }\r
1232\r
1233 Option = (EFI_DHCP4_PACKET_OPTION *) (Buffer + Offset);\r
1234 }\r
1235\r
1236 return NULL;\r
1237}\r
1238\r
1239\r
1240/**\r
1241 This function is to parse and check vendor options.\r
1242\r
1243 @param Dhcp4Option Pointer to dhcp options\r
1244 @param VendorOption Pointer to vendor options\r
1245\r
1246 @return TRUE : Valid vendor options\r
1247 @return FALSE : Invalid vendor options\r
1248\r
1249**/\r
1250BOOLEAN\r
1251PxeBcParseVendorOptions (\r
1252 IN EFI_DHCP4_PACKET_OPTION *Dhcp4Option,\r
1253 IN PXEBC_VENDOR_OPTION *VendorOption\r
1254 )\r
1255{\r
1256 UINT32 *BitMap;\r
1257 UINT8 VendorOptionLen;\r
1258 EFI_DHCP4_PACKET_OPTION *PxeOption;\r
1259 UINT8 Offset;\r
1260\r
1261 BitMap = VendorOption->BitMap;\r
1262 VendorOptionLen = Dhcp4Option->Length;\r
1263 PxeOption = (EFI_DHCP4_PACKET_OPTION *) &Dhcp4Option->Data[0];\r
1264 Offset = 0;\r
1265\r
1266 while ((Offset < VendorOptionLen) && (PxeOption->OpCode != PXEBC_DHCP4_TAG_EOP)) {\r
1267 //\r
1268 // Parse every Vendor Option and set its BitMap\r
1269 //\r
1270 switch (PxeOption->OpCode) {\r
1271\r
1272 case PXEBC_VENDOR_TAG_MTFTP_IP:\r
1273\r
e48e37fc 1274 CopyMem (&VendorOption->MtftpIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1275 break;\r
1276\r
1277 case PXEBC_VENDOR_TAG_MTFTP_CPORT:\r
1278\r
e48e37fc 1279 CopyMem (&VendorOption->MtftpCPort, PxeOption->Data, sizeof (VendorOption->MtftpCPort));\r
dc361cc5 1280 break;\r
1281\r
1282 case PXEBC_VENDOR_TAG_MTFTP_SPORT:\r
1283\r
e48e37fc 1284 CopyMem (&VendorOption->MtftpSPort, PxeOption->Data, sizeof (VendorOption->MtftpSPort));\r
dc361cc5 1285 break;\r
1286\r
1287 case PXEBC_VENDOR_TAG_MTFTP_TIMEOUT:\r
1288\r
1289 VendorOption->MtftpTimeout = *PxeOption->Data;\r
1290 break;\r
1291\r
1292 case PXEBC_VENDOR_TAG_MTFTP_DELAY:\r
1293\r
1294 VendorOption->MtftpDelay = *PxeOption->Data;\r
1295 break;\r
1296\r
1297 case PXEBC_VENDOR_TAG_DISCOVER_CTRL:\r
1298\r
1299 VendorOption->DiscoverCtrl = *PxeOption->Data;\r
1300 break;\r
1301\r
1302 case PXEBC_VENDOR_TAG_DISCOVER_MCAST:\r
1303\r
e48e37fc 1304 CopyMem (&VendorOption->DiscoverMcastIp, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
dc361cc5 1305 break;\r
1306\r
1307 case PXEBC_VENDOR_TAG_BOOT_SERVERS:\r
1308\r
1309 VendorOption->BootSvrLen = PxeOption->Length;\r
1310 VendorOption->BootSvr = (PXEBC_BOOT_SVR_ENTRY *) PxeOption->Data;\r
1311 break;\r
1312\r
1313 case PXEBC_VENDOR_TAG_BOOT_MENU:\r
1314\r
1315 VendorOption->BootMenuLen = PxeOption->Length;\r
1316 VendorOption->BootMenu = (PXEBC_BOOT_MENU_ENTRY *) PxeOption->Data;\r
1317 break;\r
1318\r
1319 case PXEBC_VENDOR_TAG_MENU_PROMPT:\r
1320\r
1321 VendorOption->MenuPromptLen = PxeOption->Length;\r
1322 VendorOption->MenuPrompt = (PXEBC_MENU_PROMPT *) PxeOption->Data;\r
1323 break;\r
1324\r
1325 case PXEBC_VENDOR_TAG_MCAST_ALLOC:\r
1326\r
e48e37fc 1327 CopyMem (&VendorOption->McastIpBase, PxeOption->Data, sizeof (EFI_IPv4_ADDRESS));\r
1328 CopyMem (&VendorOption->McastIpBlock, PxeOption->Data + 4, sizeof (VendorOption->McastIpBlock));\r
1329 CopyMem (&VendorOption->McastIpRange, PxeOption->Data + 6, sizeof (VendorOption->McastIpRange));\r
dc361cc5 1330 break;\r
1331\r
1332 case PXEBC_VENDOR_TAG_CREDENTIAL_TYPES:\r
1333\r
1334 VendorOption->CredTypeLen = PxeOption->Length;\r
1335 VendorOption->CredType = (UINT32 *) PxeOption->Data;\r
1336 break;\r
1337\r
1338 case PXEBC_VENDOR_TAG_BOOT_ITEM:\r
1339\r
e48e37fc 1340 CopyMem (&VendorOption->BootSrvType, PxeOption->Data, sizeof (VendorOption->BootSrvType));\r
1341 CopyMem (&VendorOption->BootSrvLayer, PxeOption->Data + 2, sizeof (VendorOption->BootSrvLayer));\r
dc361cc5 1342 break;\r
1343 }\r
1344\r
1345 SET_VENDOR_OPTION_BIT_MAP (BitMap, PxeOption->OpCode);\r
1346\r
1347 if (PxeOption->OpCode == PXEBC_DHCP4_TAG_PAD) {\r
1348 Offset++;\r
1349 } else {\r
1350 Offset = (UINT8) (Offset + PxeOption->Length + 2);\r
1351 }\r
1352\r
1353 PxeOption = (EFI_DHCP4_PACKET_OPTION *) (Dhcp4Option->Data + Offset);\r
1354 }\r
1355\r
1356 //\r
1357 // FixMe, return falas if invalid of any vendor option\r
1358 //\r
1359\r
1360 return TRUE;\r
1361}\r
1362\r
1363\r
1364/**\r
1365 GC_NOTO: Add function description\r
1366\r
1367 @param Str GC_NOTO: add argument description\r
1368 @param Len GC_NOTO: add argument description\r
1369\r
1370 @return GC_NOTO: add return values\r
1371\r
1372**/\r
1373VOID\r
1374PxeBcDisplayBootItem (\r
1375 IN UINT8 *Str,\r
1376 IN UINT8 Len\r
1377 )\r
1378{\r
1379 UINT8 Tmp;\r
1380\r
1381 Len = (UINT8) MIN (70, Len);\r
1382 Tmp = Str[Len];\r
1383 Str[Len] = 0;\r
1384 AsciiPrint ("%a \n", Str);\r
1385 Str[Len] = Tmp;\r
1386}\r
1387\r
1388\r
1389/**\r
1390 GC_NOTO: Add function description\r
1391\r
1392 @param Private GC_NOTO: add argument description\r
1393\r
1394 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
1395 @retval EFI_TIMEOUT GC_NOTO: Add description for return value\r
1396\r
1397**/\r
1398EFI_STATUS\r
1399PxeBcSelectBootPrompt (\r
1400 IN PXEBC_PRIVATE_DATA *Private\r
1401 )\r
1402{\r
1403 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
1404 PXEBC_VENDOR_OPTION *VendorOpt;\r
1405 EFI_EVENT TimeoutEvent;\r
1406 EFI_EVENT DescendEvent;\r
1407 EFI_INPUT_KEY InputKey;\r
1408 EFI_STATUS Status;\r
1409 UINT8 Timeout;\r
1410 UINT8 *Prompt;\r
1411 UINT8 PromptLen;\r
1412 INT32 SecCol;\r
1413 INT32 SecRow;\r
1414\r
1415 TimeoutEvent = NULL;\r
1416 DescendEvent = NULL;\r
1417\r
1418 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1419\r
1420 Packet = &Private->ProxyOffer;\r
1421 } else {\r
1422\r
1423 Packet = &Private->Dhcp4Ack;\r
1424 }\r
1425\r
1426 if (Packet->OfferType != DHCP4_PACKET_TYPE_PXE10) {\r
1427 return EFI_NOT_FOUND;\r
1428 }\r
1429\r
1430 VendorOpt = &Packet->PxeVendorOption;\r
1431\r
1432 if (!IS_VALID_BOOT_PROMPT (VendorOpt->BitMap)) {\r
1433 return EFI_SUCCESS;\r
1434 }\r
1435\r
1436 Timeout = VendorOpt->MenuPrompt->Timeout;\r
1437 Prompt = VendorOpt->MenuPrompt->Prompt;\r
1438 PromptLen = (UINT8) (VendorOpt->MenuPromptLen - 1);\r
1439\r
1440 if (Timeout == 0) {\r
1441 return EFI_SUCCESS;\r
1442 }\r
1443\r
1444 if (Timeout == 255) {\r
1445 return EFI_TIMEOUT;\r
1446 }\r
1447\r
1448 Status = gBS->CreateEvent (\r
1449 EVT_TIMER,\r
1450 TPL_CALLBACK,\r
1451 NULL,\r
1452 NULL,\r
1453 &TimeoutEvent\r
1454 );\r
1455\r
1456 if (EFI_ERROR (Status)) {\r
1457 return Status;\r
1458 }\r
1459\r
1460 Status = gBS->SetTimer (\r
1461 TimeoutEvent,\r
1462 TimerRelative,\r
1463 Timeout * TICKS_PER_SECOND\r
1464 );\r
1465\r
1466 if (EFI_ERROR (Status)) {\r
1467 goto ON_EXIT;\r
1468 }\r
1469\r
1470 Status = gBS->CreateEvent (\r
1471 EVT_TIMER,\r
1472 TPL_CALLBACK,\r
1473 NULL,\r
1474 NULL,\r
1475 &DescendEvent\r
1476 );\r
1477\r
1478 if (EFI_ERROR (Status)) {\r
1479 goto ON_EXIT;\r
1480 }\r
1481\r
1482 Status = gBS->SetTimer (\r
1483 DescendEvent,\r
1484 TimerPeriodic,\r
1485 TICKS_PER_SECOND\r
1486 );\r
1487\r
1488 if (EFI_ERROR (Status)) {\r
1489 goto ON_EXIT;\r
1490 }\r
1491\r
1492 SecCol = gST->ConOut->Mode->CursorColumn;\r
1493 SecRow = gST->ConOut->Mode->CursorRow;\r
1494\r
1495 PxeBcDisplayBootItem (Prompt, PromptLen);\r
1496\r
1497 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1498 AsciiPrint ("(%d) ", Timeout--);\r
1499\r
1500 while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
1501\r
1502 if (!EFI_ERROR (gBS->CheckEvent (DescendEvent))) {\r
1503 gST->ConOut->SetCursorPosition (gST->ConOut, SecCol + PromptLen, SecRow);\r
1504 AsciiPrint ("(%d) ", Timeout--);\r
1505 }\r
1506\r
1507 if (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1508\r
1509 gBS->Stall (10 * TICKS_PER_MS);\r
1510 continue;\r
1511 }\r
1512\r
1513 if (InputKey.ScanCode == 0) {\r
1514\r
1515 switch (InputKey.UnicodeChar) {\r
1516 case CTRL ('c'):\r
1517 Status = EFI_ABORTED;\r
1518 break;\r
1519\r
1520 case CTRL ('m'):\r
1521 case 'm':\r
1522 case 'M':\r
1523 Status = EFI_TIMEOUT;\r
1524 break;\r
1525\r
1526 default:\r
1527 continue;\r
1528 }\r
1529 } else {\r
1530\r
1531 switch (InputKey.ScanCode) {\r
1532 case SCAN_F8:\r
1533 Status = EFI_TIMEOUT;\r
1534 break;\r
1535\r
1536 case SCAN_ESC:\r
1537 Status = EFI_ABORTED;\r
1538 break;\r
1539\r
1540 default:\r
1541 continue;\r
1542 }\r
1543 }\r
1544\r
1545 break;\r
1546 }\r
1547\r
1548 gST->ConOut->SetCursorPosition (gST->ConOut, 0 , SecRow + 1);\r
1549\r
1550ON_EXIT:\r
1551\r
1552 if (DescendEvent != NULL) {\r
1553 gBS->CloseEvent (DescendEvent);\r
1554 }\r
1555\r
1556 if (TimeoutEvent != NULL) {\r
1557 gBS->CloseEvent (TimeoutEvent);\r
1558 }\r
1559\r
1560 return Status;\r
1561}\r
1562\r
1563\r
1564/**\r
1565 GC_NOTO: Add function description\r
1566\r
1567 @param Private GC_NOTO: add argument description\r
1568 @param Type GC_NOTO: add argument description\r
1569\r
1570 @retval EFI_ABORTED GC_NOTO: Add description for return value\r
1571 @retval EFI_SUCCESS GC_NOTO: Add description for return value\r
1572\r
1573**/\r
1574EFI_STATUS\r
1575PxeBcSelectBootMenu (\r
1576 IN PXEBC_PRIVATE_DATA *Private,\r
1577 OUT UINT16 *Type,\r
1578 IN BOOLEAN UseDefaultItem\r
1579 )\r
1580{\r
1581 PXEBC_CACHED_DHCP4_PACKET *Packet;\r
1582 PXEBC_VENDOR_OPTION *VendorOpt;\r
1583 EFI_INPUT_KEY InputKey;\r
1584 UINT8 MenuSize;\r
1585 UINT8 MenuNum;\r
1586 INT32 TopRow;\r
1587 UINT16 Select;\r
1588 UINT16 LastSelect;\r
1589 UINT8 Index;\r
1590 BOOLEAN Finish;\r
1591 CHAR8 Blank[70];\r
1592 PXEBC_BOOT_MENU_ENTRY *MenuItem;\r
1593 PXEBC_BOOT_MENU_ENTRY *MenuArray[PXEBC_MAX_MENU_NUM];\r
1594\r
1595 Finish = FALSE;\r
1596 Select = 1;\r
1597 Index = 0;\r
1598 *Type = 0;\r
1599\r
1600 if (Private->PxeBc.Mode->ProxyOfferReceived) {\r
1601\r
1602 Packet = &Private->ProxyOffer;\r
1603 } else {\r
1604\r
1605 Packet = &Private->Dhcp4Ack;\r
1606 }\r
1607\r
1608 ASSERT (Packet->OfferType == DHCP4_PACKET_TYPE_PXE10);\r
1609\r
1610 VendorOpt = &Packet->PxeVendorOption;\r
1611\r
1612 if (!IS_VALID_BOOT_MENU (VendorOpt->BitMap)) {\r
1613 return EFI_SUCCESS;\r
1614 }\r
1615\r
1616 SetMem (Blank, sizeof(Blank), ' ');\r
1617\r
1618 MenuSize = VendorOpt->BootMenuLen;\r
1619 MenuItem = VendorOpt->BootMenu;\r
1620\r
1621 while (MenuSize > 0) {\r
1622 MenuArray[Index] = MenuItem;\r
1623 MenuSize = (UINT8) (MenuSize - (MenuItem->DescLen + 3));\r
1624 MenuItem = (PXEBC_BOOT_MENU_ENTRY *) ((UINT8 *) MenuItem + MenuItem->DescLen + 3);\r
1625 Index++;\r
1626 }\r
1627\r
1628 if (UseDefaultItem) {\r
1629 *Type = NTOHS (MenuArray[0]->Type);\r
1630 return EFI_SUCCESS;\r
1631 }\r
1632\r
1633 MenuNum = Index;\r
1634\r
1635 for (Index = 0; Index < MenuNum; Index++) {\r
1636 PxeBcDisplayBootItem (MenuArray[Index]->DescStr, MenuArray[Index]->DescLen);\r
1637 }\r
1638\r
1639 TopRow = gST->ConOut->Mode->CursorRow - MenuNum;\r
1640\r
1641 do {\r
1642 //\r
1643 // highlight selected row\r
1644 //\r
1645 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_BLACK, EFI_LIGHTGRAY));\r
1646 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + Select);\r
1647 Blank[MenuArray[Select]->DescLen] = 0;\r
1648 AsciiPrint ("%a\r", Blank);\r
1649 PxeBcDisplayBootItem (MenuArray[Select]->DescStr, MenuArray[Select]->DescLen);\r
1650 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1651 LastSelect = Select;\r
1652\r
1653 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &InputKey) == EFI_NOT_READY) {\r
1654 gBS->Stall (10 * TICKS_PER_MS);\r
1655 }\r
1656\r
1657 if (!InputKey.ScanCode) {\r
1658 switch (InputKey.UnicodeChar) {\r
1659 case CTRL ('c'):\r
1660 InputKey.ScanCode = SCAN_ESC;\r
1661 break;\r
1662\r
1663 case CTRL ('j'): /* linefeed */\r
1664 case CTRL ('m'): /* return */\r
1665 Finish = TRUE;\r
1666 break;\r
1667\r
1668 case CTRL ('i'): /* tab */\r
1669 case ' ':\r
1670 case 'd':\r
1671 case 'D':\r
1672 InputKey.ScanCode = SCAN_DOWN;\r
1673 break;\r
1674\r
1675 case CTRL ('h'): /* backspace */\r
1676 case 'u':\r
1677 case 'U':\r
1678 InputKey.ScanCode = SCAN_UP;\r
1679 break;\r
1680\r
1681 default:\r
1682 InputKey.ScanCode = 0;\r
1683 }\r
1684 }\r
1685\r
1686 switch (InputKey.ScanCode) {\r
1687 case SCAN_LEFT:\r
1688 case SCAN_UP:\r
1689 if (Select) {\r
1690 --Select;\r
1691 }\r
1692\r
1693 break;\r
1694\r
1695 case SCAN_DOWN:\r
1696 case SCAN_RIGHT:\r
1697 if (++Select == MenuNum) {\r
1698 --Select;\r
1699 }\r
1700\r
1701 break;\r
1702\r
1703 case SCAN_PAGE_UP:\r
1704 case SCAN_HOME:\r
1705 Select = 0;\r
1706 break;\r
1707\r
1708 case SCAN_PAGE_DOWN:\r
1709 case SCAN_END:\r
1710 Select = (UINT16) (MenuNum - 1);\r
1711 break;\r
1712\r
1713 case SCAN_ESC:\r
1714 return EFI_ABORTED;\r
1715 }\r
1716\r
1717 /* unhighlight last selected row */\r
1718 gST->ConOut->SetAttribute (gST->ConOut, EFI_TEXT_ATTR (EFI_LIGHTGRAY, EFI_BLACK));\r
1719 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + LastSelect);\r
1720 Blank[MenuArray[LastSelect]->DescLen] = 0;\r
1721 AsciiPrint ("%a\r", Blank);\r
1722 PxeBcDisplayBootItem (MenuArray[LastSelect]->DescStr, MenuArray[LastSelect]->DescLen);\r
1723 gST->ConOut->SetCursorPosition (gST->ConOut, 0, TopRow + MenuNum);\r
1724 } while (!Finish);\r
1725\r
1726 //\r
1727 // Swap the byte order\r
1728 //\r
1729 *Type = NTOHS (MenuArray[Select]->Type);\r
1730\r
1731 return EFI_SUCCESS;\r
1732}\r
1733\r