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