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