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