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