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