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