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