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