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