]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
Fixed a bug for OPTION_NII(62) defined in RFC 5970.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp6.c
1 /** @file
2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
3
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "PxeBcImpl.h"
17
18
19 /**
20 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
21
22 @param[in] Buffer The pointer to the option buffer.
23 @param[in] Length Length of the option buffer.
24 @param[in] OptTag The required option tag.
25
26 @retval NULL Failed to parse the required option.
27 @retval Others The postion of the required option in buffer.
28
29 **/
30 EFI_DHCP6_PACKET_OPTION *
31 PxeBcParseDhcp6Options (
32 IN UINT8 *Buffer,
33 IN UINT32 Length,
34 IN UINT16 OptTag
35 )
36 {
37 EFI_DHCP6_PACKET_OPTION *Option;
38 UINT32 Offset;
39
40 Option = (EFI_DHCP6_PACKET_OPTION *) Buffer;
41 Offset = 0;
42
43 //
44 // OpLen and OpCode here are both stored in network order.
45 //
46 while (Offset < Length) {
47
48 if (NTOHS (Option->OpCode) == OptTag) {
49
50 return Option;
51 }
52
53 Offset += (NTOHS(Option->OpLen) + 4);
54 Option = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset);
55 }
56
57 return NULL;
58 }
59
60
61 /**
62 Build the options buffer for the DHCPv6 request packet.
63
64 @param[in] Private The pointer to PxeBc private data.
65 @param[out] OptList The pointer to the option pointer array.
66 @param[in] Buffer The pointer to the buffer to contain the option list.
67
68 @return Index The count of the built-in options.
69
70 **/
71 UINT32
72 PxeBcBuildDhcp6Options (
73 IN PXEBC_PRIVATE_DATA *Private,
74 OUT EFI_DHCP6_PACKET_OPTION **OptList,
75 IN UINT8 *Buffer
76 )
77 {
78 PXEBC_DHCP6_OPTION_ENTRY OptEnt;
79 UINT32 Index;
80 UINT16 Value;
81
82 Index = 0;
83 OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer;
84
85 //
86 // Append client option request option
87 //
88 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ORO);
89 OptList[Index]->OpLen = HTONS (4);
90 OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data;
91 OptEnt.Oro->OpCode[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL);
92 OptEnt.Oro->OpCode[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM);
93 Index++;
94 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
95
96 //
97 // Append client network device interface option
98 //
99 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_UNDI);
100 OptList[Index]->OpLen = HTONS ((UINT16)3);
101 OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data;
102
103 if (Private->Nii != NULL) {
104 OptEnt.Undi->Type = Private->Nii->Type;
105 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
106 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
107 } else {
108 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;
109 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
110 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
111 }
112
113 Index++;
114 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
115
116 //
117 // Append client system architecture option
118 //
119 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ARCH);
120 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_ARCH));
121 OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index]->Data;
122 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
123 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
124 Index++;
125 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
126
127 //
128 // Append vendor class option to store the PXE class identifier.
129 //
130 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS);
131 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS));
132 OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data;
133 OptEnt.VendorClass->Vendor = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM);
134 OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (PXEBC_CLASS_ID));
135 CopyMem (
136 &OptEnt.VendorClass->ClassId,
137 DEFAULT_CLASS_ID_DATA,
138 sizeof (PXEBC_CLASS_ID)
139 );
140 PxeBcUintnToAscDecWithFormat (
141 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
142 OptEnt.VendorClass->ClassId.ArchitectureType,
143 sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)
144 );
145
146 if (Private->Nii != NULL) {
147 CopyMem (
148 OptEnt.VendorClass->ClassId.InterfaceName,
149 Private->Nii->StringId,
150 sizeof (OptEnt.VendorClass->ClassId.InterfaceName)
151 );
152 PxeBcUintnToAscDecWithFormat (
153 Private->Nii->MajorVer,
154 OptEnt.VendorClass->ClassId.UndiMajor,
155 sizeof (OptEnt.VendorClass->ClassId.UndiMajor)
156 );
157 PxeBcUintnToAscDecWithFormat (
158 Private->Nii->MinorVer,
159 OptEnt.VendorClass->ClassId.UndiMinor,
160 sizeof (OptEnt.VendorClass->ClassId.UndiMinor)
161 );
162 }
163
164 Index++;
165
166 return Index;
167 }
168
169
170 /**
171 Cache the DHCPv6 packet.
172
173 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
174 @param[in] Src The pointer to the DHCPv6 packet to be cached.
175
176 **/
177 VOID
178 PxeBcCacheDhcp6Packet (
179 IN EFI_DHCP6_PACKET *Dst,
180 IN EFI_DHCP6_PACKET *Src
181 )
182 {
183 ASSERT (Dst->Size >= Src->Length);
184
185 CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);
186 Dst->Length = Src->Length;
187 }
188
189
190 /**
191 Free all the nodes in the list for boot file.
192
193 @param[in] Head The pointer to the head of list.
194
195 **/
196 VOID
197 PxeBcFreeBootFileOption (
198 IN LIST_ENTRY *Head
199 )
200 {
201 LIST_ENTRY *Entry;
202 LIST_ENTRY *NextEntry;
203 PXEBC_DHCP6_OPTION_NODE *Node;
204
205 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, Head) {
206 Node = NET_LIST_USER_STRUCT (Entry, PXEBC_DHCP6_OPTION_NODE, Link);
207 RemoveEntryList (Entry);
208 FreePool (Node);
209 }
210 }
211
212
213 /**
214 Parse the Boot File URL option.
215
216 @param[out] FileName The pointer to the boot file name.
217 @param[in, out] SrvAddr The pointer to the boot server address.
218 @param[in] BootFile The pointer to the boot file URL option data.
219 @param[in] Length The length of the boot file URL option data.
220
221 @retval EFI_ABORTED User cancel operation.
222 @retval EFI_SUCCESS Selected the boot menu successfully.
223 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
224
225 **/
226 EFI_STATUS
227 PxeBcExtractBootFileUrl (
228 OUT UINT8 **FileName,
229 IN OUT EFI_IPv6_ADDRESS *SrvAddr,
230 IN CHAR8 *BootFile,
231 IN UINT16 Length
232 )
233 {
234 UINT16 PrefixLen;
235 UINT8 *BootFileNamePtr;
236 UINT8 *BootFileName;
237 UINT16 BootFileNameLen;
238 CHAR8 *TmpStr;
239 CHAR8 *ServerAddressOption;
240 CHAR8 *ServerAddress;
241 EFI_STATUS Status;
242
243 //
244 // The format of the Boot File URL option is:
245 //
246 // 0 1 2 3
247 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
248 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
249 // | OPT_BOOTFILE_URL | option-len |
250 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
251 // | |
252 // . bootfile-url (variable length) .
253 // | |
254 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
255 //
256
257 //
258 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
259 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
260 // As an example where the BOOTFILE_NAME is the EFI loader and
261 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
262 //
263 PrefixLen = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX);
264
265 if (Length <= PrefixLen ||
266 CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0) {
267 return EFI_NOT_FOUND;
268 }
269
270 BootFile = BootFile + PrefixLen;
271 Length = (UINT16) (Length - PrefixLen);
272
273 TmpStr = (CHAR8 *) AllocateZeroPool (Length + 1);
274 if (TmpStr == NULL) {
275 return EFI_OUT_OF_RESOURCES;
276 }
277
278 CopyMem (TmpStr, BootFile, Length);
279 TmpStr[Length] = '\0';
280
281 //
282 // Get the part of SERVER_ADDRESS string.
283 //
284 ServerAddressOption = TmpStr;
285 if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) {
286 FreePool (TmpStr);
287 return EFI_INVALID_PARAMETER;
288 }
289
290 ServerAddressOption ++;
291 ServerAddress = ServerAddressOption;
292 while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {
293 ServerAddress++;
294 }
295
296 if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {
297 FreePool (TmpStr);
298 return EFI_INVALID_PARAMETER;
299 }
300
301 *ServerAddress = '\0';
302
303 //
304 // Convert the string of server address to Ipv6 address format and store it.
305 //
306 Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);
307 if (EFI_ERROR (Status)) {
308 FreePool (TmpStr);
309 return Status;
310 }
311
312 //
313 // Get the part of BOOTFILE_NAME string.
314 //
315 BootFileNamePtr = (UINT8*)((UINTN)ServerAddress + 1);
316 if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {
317 FreePool (TmpStr);
318 return EFI_INVALID_PARAMETER;
319 }
320
321 ++BootFileNamePtr;
322 BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);
323 if (BootFileNameLen != 0 || FileName != NULL) {
324 BootFileName = (UINT8 *) AllocateZeroPool (BootFileNameLen);
325 if (BootFileName == NULL) {
326 FreePool (TmpStr);
327 return EFI_OUT_OF_RESOURCES;
328 }
329
330 CopyMem (BootFileName, BootFileNamePtr, BootFileNameLen);
331 BootFileName[BootFileNameLen - 1] = '\0';
332 *FileName = BootFileName;
333 }
334
335
336 FreePool (TmpStr);
337
338 return EFI_SUCCESS;
339 }
340
341
342 /**
343 Parse the Boot File Parameter option.
344
345 @param[in] BootFilePara The pointer to boot file parameter option data.
346 @param[out] BootFileSize The pointer to the parsed boot file size.
347
348 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
349 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
350
351 **/
352 EFI_STATUS
353 PxeBcExtractBootFileParam (
354 IN CHAR8 *BootFilePara,
355 OUT UINT16 *BootFileSize
356 )
357 {
358 UINT16 Length;
359 UINT8 Index;
360 UINT8 Digit;
361 UINT32 Size;
362
363 CopyMem (&Length, BootFilePara, sizeof (UINT16));
364 Length = NTOHS (Length);
365
366 //
367 // The BootFile Size should be 1~5 byte ASCII strings
368 //
369 if (Length < 1 || Length > 5) {
370 return EFI_NOT_FOUND;
371 }
372
373 //
374 // Extract the value of BootFile Size.
375 //
376 BootFilePara = BootFilePara + sizeof (UINT16);
377 Size = 0;
378 for (Index = 0; Index < Length; Index++) {
379 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit, *(BootFilePara + Index)))) {
380 return EFI_NOT_FOUND;
381 }
382
383 Size = (Size + Digit) * 10;
384 }
385
386 Size = Size / 10;
387 if (Size > PXEBC_DHCP6_MAX_BOOT_FILE_SIZE) {
388 return EFI_NOT_FOUND;
389 }
390
391 *BootFileSize = (UINT16) Size;
392 return EFI_SUCCESS;
393 }
394
395
396 /**
397 Parse the cached DHCPv6 packet, including all the options.
398
399 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
400
401 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
402 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
403
404 **/
405 EFI_STATUS
406 PxeBcParseDhcp6Packet (
407 IN PXEBC_DHCP6_PACKET_CACHE *Cache6
408 )
409 {
410 EFI_DHCP6_PACKET *Offer;
411 EFI_DHCP6_PACKET_OPTION **Options;
412 EFI_DHCP6_PACKET_OPTION *Option;
413 PXEBC_OFFER_TYPE OfferType;
414 BOOLEAN IsProxyOffer;
415 BOOLEAN IsPxeOffer;
416 UINT32 Offset;
417 UINT32 Length;
418 UINT32 EnterpriseNum;
419
420 IsProxyOffer = TRUE;
421 IsPxeOffer = FALSE;
422 Offer = &Cache6->Packet.Offer;
423 Options = Cache6->OptList;
424
425 ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));
426
427 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option);
428 Offset = 0;
429 Length = GET_DHCP6_OPTION_SIZE (Offer);
430
431 //
432 // OpLen and OpCode here are both stored in network order, since they are from original packet.
433 //
434 while (Offset < Length) {
435
436 if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_IA_NA) {
437 Options[PXEBC_DHCP6_IDX_IA_NA] = Option;
438 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_URL) {
439 //
440 // The server sends this option to inform the client about an URL to a boot file.
441 //
442 Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option;
443 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM) {
444 Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;
445 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_VENDOR_CLASS) {
446 Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;
447 }
448
449 Offset += (NTOHS (Option->OpLen) + 4);
450 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset);
451 }
452
453 //
454 // The offer with assigned client address is a proxy offer.
455 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
456 //
457 Option = Options[PXEBC_DHCP6_IDX_IA_NA];
458 if (Option != NULL && NTOHS(Option->OpLen) >= 12) {
459 Option = PxeBcParseDhcp6Options (
460 Option->Data + 12,
461 NTOHS (Option->OpLen),
462 PXEBC_DHCP6_OPT_STATUS_CODE
463 );
464 if (Option != NULL && Option->Data[0] == 0) {
465 IsProxyOffer = FALSE;
466 }
467 }
468
469 //
470 // The offer with "PXEClient" is a pxe offer.
471 //
472 Option = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS];
473 EnterpriseNum = PXEBC_DHCP6_ENTERPRISE_NUM;
474 if (Option != NULL &&
475 NTOHS(Option->OpLen) >= 13 &&
476 CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 &&
477 CompareMem (&Option->Data[4], DEFAULT_CLASS_ID_DATA, 9) == 0) {
478 IsPxeOffer = TRUE;
479 }
480
481 //
482 // Determine offer type of the dhcp6 packet.
483 //
484 if (IsPxeOffer) {
485 //
486 // It's a binl offer only with PXEClient.
487 //
488 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
489 } else {
490 //
491 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
492 //
493 OfferType = PxeOfferTypeDhcpOnly;
494 }
495
496 Cache6->OfferType = OfferType;
497
498 return EFI_SUCCESS;
499 }
500
501
502 /**
503 Cache the DHCPv6 ack packet, and parse it on demand.
504
505 @param[in] Private The pointer to PxeBc private data.
506 @param[in] Ack The pointer to the DHCPv6 ack packet.
507 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
508
509 **/
510 VOID
511 PxeBcCopyDhcp6Ack (
512 IN PXEBC_PRIVATE_DATA *Private,
513 IN EFI_DHCP6_PACKET *Ack,
514 IN BOOLEAN Verified
515 )
516 {
517 EFI_PXE_BASE_CODE_MODE *Mode;
518
519 Mode = Private->PxeBc.Mode;
520
521 PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack);
522
523 if (Verified) {
524 //
525 // Parse the ack packet and store it into mode data if needed.
526 //
527 PxeBcParseDhcp6Packet (&Private->DhcpAck.Dhcp6);
528 CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length);
529 Mode->DhcpAckReceived = TRUE;
530 }
531 }
532
533
534 /**
535 Cache the DHCPv6 proxy offer packet according to the received order.
536
537 @param[in] Private The pointer to PxeBc private data.
538 @param[in] OfferIndex The received order of offer packets.
539
540 **/
541 VOID
542 PxeBcCopyDhcp6Proxy (
543 IN PXEBC_PRIVATE_DATA *Private,
544 IN UINT32 OfferIndex
545 )
546 {
547 EFI_PXE_BASE_CODE_MODE *Mode;
548 EFI_DHCP6_PACKET *Offer;
549
550 ASSERT (OfferIndex < Private->OfferNum);
551 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
552
553 Mode = Private->PxeBc.Mode;
554 Offer = &Private->OfferBuffer[OfferIndex].Dhcp6.Packet.Offer;
555
556 //
557 // Cache the proxy offer packet and parse it.
558 //
559 PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer);
560 PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6);
561
562 //
563 // Store this packet into mode data.
564 //
565 CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length);
566 Mode->ProxyOfferReceived = TRUE;
567 }
568
569
570 /**
571 Retry to request bootfile name by the BINL offer.
572
573 @param[in] Private The pointer to PxeBc private data.
574 @param[in] Index The received order of offer packets.
575
576 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
577 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
578
579 **/
580 EFI_STATUS
581 PxeBcRetryDhcp6Binl (
582 IN PXEBC_PRIVATE_DATA *Private,
583 IN UINT32 Index
584 )
585 {
586 EFI_PXE_BASE_CODE_MODE *Mode;
587 PXEBC_DHCP6_PACKET_CACHE *Offer;
588 PXEBC_DHCP6_PACKET_CACHE *Cache6;
589 EFI_IP_ADDRESS ServerIp;
590 EFI_STATUS Status;
591
592 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
593 ASSERT (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl ||
594 Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl);
595
596 Mode = Private->PxeBc.Mode;
597 Private->IsDoDiscover = FALSE;
598 Offer = &Private->OfferBuffer[Index].Dhcp6;
599
600 ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
601 //
602 // Parse out the next server address from the last offer, and store it
603 //
604 Status = PxeBcExtractBootFileUrl (
605 NULL,
606 &ServerIp.v6,
607 (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
608 NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
609 );
610 if (EFI_ERROR (Status)) {
611 return Status;
612 }
613
614 //
615 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
616 //
617 Status = PxeBcDhcp6Discover (
618 Private,
619 0,
620 NULL,
621 FALSE,
622 &ServerIp
623 );
624 if (EFI_ERROR (Status)) {
625 return Status;
626 }
627
628 Cache6 = &Private->ProxyOffer.Dhcp6;
629 Status = PxeBcParseDhcp6Packet (Cache6);
630 if (EFI_ERROR (Status)) {
631 return Status;
632 }
633
634 if (Cache6->OfferType != PxeOfferTypeProxyPxe10 &&
635 Cache6->OfferType != PxeOfferTypeProxyWfm11a &&
636 Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
637 //
638 // This BINL ack doesn't have discovery option set or multicast option set
639 // or bootfile name specified.
640 //
641 return EFI_DEVICE_ERROR;
642 }
643
644 Mode->ProxyOfferReceived = TRUE;
645 CopyMem (
646 &Mode->ProxyOffer.Dhcpv6,
647 &Cache6->Packet.Offer.Dhcp6,
648 Cache6->Packet.Offer.Length
649 );
650
651 return EFI_SUCCESS;
652 }
653
654
655 /**
656 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
657
658 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
659 @param[in] RcvdOffer The pointer to the received offer packet.
660
661 **/
662 VOID
663 PxeBcCacheDhcp6Offer (
664 IN PXEBC_PRIVATE_DATA *Private,
665 IN EFI_DHCP6_PACKET *RcvdOffer
666 )
667 {
668 PXEBC_DHCP6_PACKET_CACHE *Cache6;
669 EFI_DHCP6_PACKET *Offer;
670 PXEBC_OFFER_TYPE OfferType;
671
672 Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;
673 Offer = &Cache6->Packet.Offer;
674
675 //
676 // Cache the content of DHCPv6 packet firstly.
677 //
678 PxeBcCacheDhcp6Packet (Offer, RcvdOffer);
679
680 //
681 // Validate the DHCPv6 packet, and parse the options and offer type.
682 //
683 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) {
684 return ;
685 }
686
687 //
688 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
689 //
690 OfferType = Cache6->OfferType;
691 ASSERT (OfferType < PxeOfferTypeMax);
692 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
693
694 if (IS_PROXY_OFFER (OfferType)) {
695 //
696 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
697 //
698 Private->IsProxyRecved = TRUE;
699
700 if (OfferType == PxeOfferTypeProxyBinl) {
701 //
702 // Cache all proxy BINL offers.
703 //
704 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
705 Private->OfferCount[OfferType]++;
706 } else if (Private->OfferCount[OfferType] > 0) {
707 //
708 // Only cache the first PXE10/WFM11a offer, and discard the others.
709 //
710 Private->OfferIndex[OfferType][0] = Private->OfferNum;
711 Private->OfferCount[OfferType] = 1;
712 } else {
713 return;
714 }
715 } else {
716 //
717 // It's a DHCPv6 offer with yiaddr, and cache them all.
718 //
719 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
720 Private->OfferCount[OfferType]++;
721 }
722
723 Private->OfferNum++;
724 }
725
726
727 /**
728 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
729
730 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
731
732 **/
733 VOID
734 PxeBcSelectDhcp6Offer (
735 IN PXEBC_PRIVATE_DATA *Private
736 )
737 {
738 UINT32 Index;
739 UINT32 OfferIndex;
740 PXEBC_OFFER_TYPE OfferType;
741
742 Private->SelectIndex = 0;
743
744 if (Private->IsOfferSorted) {
745 //
746 // Select offer by default policy.
747 //
748 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
749 //
750 // 1. DhcpPxe10 offer
751 //
752 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
753
754 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
755 //
756 // 2. DhcpWfm11a offer
757 //
758 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
759
760 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
761 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {
762 //
763 // 3. DhcpOnly offer and ProxyPxe10 offer.
764 //
765 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
766 Private->SelectProxyType = PxeOfferTypeProxyPxe10;
767
768 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
769 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {
770 //
771 // 4. DhcpOnly offer and ProxyWfm11a offer.
772 //
773 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
774 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
775
776 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
777 //
778 // 5. DhcpBinl offer.
779 //
780 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
781
782 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
783 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {
784 //
785 // 6. DhcpOnly offer and ProxyBinl offer.
786 //
787 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
788 Private->SelectProxyType = PxeOfferTypeProxyBinl;
789
790 } else {
791 //
792 // 7. DhcpOnly offer with bootfilename.
793 //
794 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
795 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
796 if (Private->OfferBuffer[OfferIndex].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL) {
797 Private->SelectIndex = OfferIndex + 1;
798 break;
799 }
800 }
801 }
802 } else {
803 //
804 // Select offer by received order.
805 //
806 for (Index = 0; Index < Private->OfferNum; Index++) {
807
808 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;
809
810 if (IS_PROXY_OFFER (OfferType)) {
811 //
812 // Skip proxy offers
813 //
814 continue;
815 }
816
817 if (!Private->IsProxyRecved &&
818 OfferType == PxeOfferTypeDhcpOnly &&
819 Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
820 //
821 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
822 //
823 continue;
824 }
825
826 Private->SelectIndex = Index + 1;
827 break;
828 }
829 }
830 }
831
832
833 /**
834 Handle the DHCPv6 offer packet.
835
836 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
837
838 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
839 @retval EFI_NO_RESPONSE No response to the following request packet.
840
841 **/
842 EFI_STATUS
843 PxeBcHandleDhcp6Offer (
844 IN PXEBC_PRIVATE_DATA *Private
845 )
846 {
847 PXEBC_DHCP6_PACKET_CACHE *Cache6;
848 EFI_STATUS Status;
849 PXEBC_OFFER_TYPE OfferType;
850 UINT32 ProxyIndex;
851 UINT32 SelectIndex;
852 UINT32 Index;
853
854 ASSERT (Private->SelectIndex > 0);
855 SelectIndex = (UINT32) (Private->SelectIndex - 1);
856 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
857 Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6;
858 Status = EFI_SUCCESS;
859
860 if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {
861 //
862 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
863 //
864 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) {
865 Status = EFI_NO_RESPONSE;
866 }
867 } else if (Cache6->OfferType == PxeOfferTypeDhcpOnly) {
868
869 if (Private->IsProxyRecved) {
870 //
871 // DhcpOnly offer is selected, so need try to request bootfilename.
872 //
873 ProxyIndex = 0;
874 if (Private->IsOfferSorted) {
875 //
876 // The proxy offer should be determined if select by default policy.
877 // IsOfferSorted means all offers are labeled by OfferIndex.
878 //
879 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
880
881 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
882 //
883 // Try all the cached ProxyBinl offer one by one to request bootfilename.
884 //
885 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
886
887 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
888 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) {
889 break;
890 }
891 }
892 if (Index == Private->OfferCount[Private->SelectProxyType]) {
893 Status = EFI_NO_RESPONSE;
894 }
895 } else {
896 //
897 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
898 //
899 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
900 }
901 } else {
902 //
903 // The proxy offer should not be determined if select by received order.
904 //
905 Status = EFI_NO_RESPONSE;
906
907 for (Index = 0; Index < Private->OfferNum; Index++) {
908
909 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;
910
911 if (!IS_PROXY_OFFER (OfferType)) {
912 //
913 // Skip non proxy dhcp offers.
914 //
915 continue;
916 }
917
918 if (OfferType == PxeOfferTypeProxyBinl) {
919 //
920 // Try all the cached ProxyBinl offer one by one to request bootfilename.
921 //
922 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, Index))) {
923 continue;
924 }
925 }
926
927 Private->SelectProxyType = OfferType;
928 ProxyIndex = Index;
929 Status = EFI_SUCCESS;
930 break;
931 }
932 }
933
934 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {
935 //
936 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
937 //
938 PxeBcCopyDhcp6Proxy (Private, ProxyIndex);
939 }
940 } else {
941 //
942 // Othewise, the bootfilename must be included in DhcpOnly offer.
943 //
944 ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
945 }
946 }
947
948 if (!EFI_ERROR (Status)) {
949 //
950 // All PXE boot information is ready by now.
951 //
952 PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE);
953 Private->PxeBc.Mode->DhcpDiscoverValid = TRUE;
954 }
955
956 return Status;
957 }
958
959
960 /**
961 Unregister the address by Ip6Config protocol.
962
963 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
964
965 **/
966 VOID
967 PxeBcUnregisterIp6Address (
968 IN PXEBC_PRIVATE_DATA *Private
969 )
970 {
971 if (Private->Ip6Policy != PXEBC_IP6_POLICY_MAX) {
972 //
973 // PXE driver change the policy of IP6 driver, it's a chance to recover.
974 // Keep the point and there is no enough requirements to do recovery.
975 //
976 }
977 }
978
979
980 /**
981 Register the ready address by Ip6Config protocol.
982
983 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
984 @param[in] Address The pointer to the ready address.
985
986 @retval EFI_SUCCESS Registered the address succesfully.
987 @retval Others Failed to register the address.
988
989 **/
990 EFI_STATUS
991 PxeBcRegisterIp6Address (
992 IN PXEBC_PRIVATE_DATA *Private,
993 IN EFI_IPv6_ADDRESS *Address
994 )
995 {
996 EFI_IP6_PROTOCOL *Ip6;
997 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
998 EFI_IP6_CONFIG_POLICY Policy;
999 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;
1000 UINTN DataSize;
1001 EFI_EVENT TimeOutEvt;
1002 EFI_EVENT MappedEvt;
1003 EFI_STATUS Status;
1004
1005 Status = EFI_SUCCESS;
1006 TimeOutEvt = NULL;
1007 MappedEvt = NULL;
1008 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
1009 Ip6Cfg = Private->Ip6Cfg;
1010 Ip6 = Private->Ip6;
1011
1012 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
1013 CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS));
1014
1015 //
1016 // Get and store the current policy of IP6 driver.
1017 //
1018 Status = Ip6Cfg->GetData (
1019 Ip6Cfg,
1020 Ip6ConfigDataTypePolicy,
1021 &DataSize,
1022 &Private->Ip6Policy
1023 );
1024 if (EFI_ERROR (Status)) {
1025 goto ON_EXIT;
1026 }
1027
1028 //
1029 // There is no channel between IP6 and PXE driver about address setting,
1030 // so it has to set the new address by Ip6ConfigProtocol manually.
1031 //
1032 Policy = Ip6ConfigPolicyManual;
1033 Status = Ip6Cfg->SetData (
1034 Ip6Cfg,
1035 Ip6ConfigDataTypePolicy,
1036 sizeof(EFI_IP6_CONFIG_POLICY),
1037 &Policy
1038 );
1039 if (EFI_ERROR (Status)) {
1040 //
1041 // There is no need to recover later.
1042 //
1043 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;
1044 goto ON_EXIT;
1045 }
1046
1047 //
1048 // Create a timer as setting address timeout event since DAD in IP6 driver.
1049 //
1050 Status = gBS->CreateEvent (
1051 EVT_TIMER,
1052 TPL_CALLBACK,
1053 NULL,
1054 NULL,
1055 &TimeOutEvt
1056 );
1057 if (EFI_ERROR (Status)) {
1058 goto ON_EXIT;
1059 }
1060
1061 //
1062 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1063 //
1064 Status = gBS->CreateEvent (
1065 EVT_NOTIFY_SIGNAL,
1066 TPL_NOTIFY,
1067 PxeBcCommonNotify,
1068 &Private->IsAddressOk,
1069 &MappedEvt
1070 );
1071 if (EFI_ERROR (Status)) {
1072 goto ON_EXIT;
1073 }
1074
1075 Status = Ip6Cfg->RegisterDataNotify (
1076 Ip6Cfg,
1077 Ip6ConfigDataTypeManualAddress,
1078 MappedEvt
1079 );
1080 if (EFI_ERROR(Status)) {
1081 goto ON_EXIT;
1082 }
1083
1084 Status = Ip6Cfg->SetData (
1085 Ip6Cfg,
1086 Ip6ConfigDataTypeManualAddress,
1087 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS),
1088 &CfgAddr
1089 );
1090 if (EFI_ERROR(Status) && Status != EFI_NOT_READY) {
1091 goto ON_EXIT;
1092 }
1093
1094 //
1095 // Start the 5 secondes timer to wait for setting address.
1096 //
1097 Status = EFI_NO_MAPPING;
1098 gBS->SetTimer (TimeOutEvt, TimerRelative, PXEBC_DHCP6_MAPPING_TIMEOUT);
1099
1100 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
1101 Ip6->Poll (Ip6);
1102 if (Private->IsAddressOk) {
1103 Status = EFI_SUCCESS;
1104 break;
1105 }
1106 }
1107
1108 ON_EXIT:
1109 if (MappedEvt != NULL) {
1110 Ip6Cfg->UnregisterDataNotify (
1111 Ip6Cfg,
1112 Ip6ConfigDataTypeManualAddress,
1113 MappedEvt
1114 );
1115 gBS->CloseEvent (MappedEvt);
1116 }
1117 if (TimeOutEvt != NULL) {
1118 gBS->CloseEvent (TimeOutEvt);
1119 }
1120 return Status;
1121 }
1122
1123
1124 /**
1125 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1126 to intercept events that occurred in the configuration process.
1127
1128 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1129 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1130 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1131 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1132 state transition.
1133 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1134 @param[out] NewPacket The packet that is used to replace the Packet above.
1135
1136 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1137 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1138 driver will continue to wait for more packets.
1139 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1140
1141 **/
1142 EFI_STATUS
1143 EFIAPI
1144 PxeBcDhcp6CallBack (
1145 IN EFI_DHCP6_PROTOCOL *This,
1146 IN VOID *Context,
1147 IN EFI_DHCP6_STATE CurrentState,
1148 IN EFI_DHCP6_EVENT Dhcp6Event,
1149 IN EFI_DHCP6_PACKET *Packet,
1150 OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL
1151 )
1152 {
1153 PXEBC_PRIVATE_DATA *Private;
1154 EFI_PXE_BASE_CODE_MODE *Mode;
1155 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
1156 EFI_DHCP6_PACKET *SelectAd;
1157 EFI_STATUS Status;
1158 BOOLEAN Received;
1159
1160 if ((Dhcp6Event != Dhcp6RcvdAdvertise) &&
1161 (Dhcp6Event != Dhcp6SelectAdvertise) &&
1162 (Dhcp6Event != Dhcp6SendSolicit) &&
1163 (Dhcp6Event != Dhcp6SendRequest) &&
1164 (Dhcp6Event != Dhcp6RcvdReply)) {
1165 return EFI_SUCCESS;
1166 }
1167
1168 ASSERT (Packet != NULL);
1169
1170 Private = (PXEBC_PRIVATE_DATA *) Context;
1171 Mode = Private->PxeBc.Mode;
1172 Callback = Private->PxeBcCallback;
1173
1174 //
1175 // Callback to user when any traffic ocurred if has.
1176 //
1177 if (Dhcp6Event != Dhcp6SelectAdvertise && Callback != NULL) {
1178 Received = (BOOLEAN) (Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);
1179 Status = Callback->Callback (
1180 Callback,
1181 Private->Function,
1182 Received,
1183 Packet->Length,
1184 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp6
1185 );
1186 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
1187 return EFI_ABORTED;
1188 }
1189 }
1190
1191 Status = EFI_SUCCESS;
1192
1193 switch (Dhcp6Event) {
1194
1195 case Dhcp6SendSolicit:
1196 //
1197 // Cache the dhcp discover packet to mode data directly.
1198 //
1199 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length);
1200 break;
1201
1202 case Dhcp6RcvdAdvertise:
1203 Status = EFI_NOT_READY;
1204 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
1205 //
1206 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1207 // the OfferIndex and OfferCount.
1208 //
1209 PxeBcCacheDhcp6Offer (Private, Packet);
1210 }
1211 break;
1212
1213 case Dhcp6SendRequest:
1214 //
1215 // Store the request packet as seed packet for discover.
1216 //
1217 if (Private->Dhcp6Request != NULL) {
1218 FreePool (Private->Dhcp6Request);
1219 }
1220 Private->Dhcp6Request = AllocateZeroPool (Packet->Size);
1221 if (Private->Dhcp6Request != NULL) {
1222 CopyMem (Private->Dhcp6Request, Packet, Packet->Size);
1223 }
1224 break;
1225
1226 case Dhcp6SelectAdvertise:
1227 //
1228 // Select offer by the default policy or by order, and record the SelectIndex
1229 // and SelectProxyType.
1230 //
1231 PxeBcSelectDhcp6Offer (Private);
1232
1233 if (Private->SelectIndex == 0) {
1234 Status = EFI_ABORTED;
1235 } else {
1236 ASSERT (NewPacket != NULL);
1237 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;
1238 *NewPacket = AllocateZeroPool (SelectAd->Size);
1239 ASSERT (*NewPacket != NULL);
1240 CopyMem (*NewPacket, SelectAd, SelectAd->Size);
1241 }
1242 break;
1243
1244 case Dhcp6RcvdReply:
1245 //
1246 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1247 // without verification.
1248 //
1249 ASSERT (Private->SelectIndex != 0);
1250 PxeBcCopyDhcp6Ack (Private, Packet, FALSE);
1251 break;
1252
1253 default:
1254 ASSERT (0);
1255 }
1256
1257 return Status;
1258 }
1259
1260
1261 /**
1262 Build and send out the request packet for the bootfile, and parse the reply.
1263
1264 @param[in] Private The pointer to PxeBc private data.
1265 @param[in] Type PxeBc option boot item type.
1266 @param[in] Layer The pointer to option boot item layer.
1267 @param[in] UseBis Use BIS or not.
1268 @param[in] DestIp The pointer to the server address.
1269
1270 @retval EFI_SUCCESS Successfully discovered the boot file.
1271 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1272 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1273 @retval Others Failed to discover the boot file.
1274
1275 **/
1276 EFI_STATUS
1277 PxeBcDhcp6Discover (
1278 IN PXEBC_PRIVATE_DATA *Private,
1279 IN UINT16 Type,
1280 IN UINT16 *Layer,
1281 IN BOOLEAN UseBis,
1282 IN EFI_IP_ADDRESS *DestIp
1283 )
1284 {
1285 EFI_PXE_BASE_CODE_UDP_PORT SrcPort;
1286 EFI_PXE_BASE_CODE_UDP_PORT DestPort;
1287 EFI_PXE_BASE_CODE_MODE *Mode;
1288 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
1289 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover;
1290 UINTN DiscoverLen;
1291 EFI_DHCP6_PACKET *Request;
1292 UINTN RequestLen;
1293 EFI_DHCP6_PACKET *Reply;
1294 UINT8 *RequestOpt;
1295 UINT8 *DiscoverOpt;
1296 UINTN ReadSize;
1297 UINT16 OpFlags;
1298 UINT16 OpCode;
1299 UINT16 OpLen;
1300 UINT32 Xid;
1301 EFI_STATUS Status;
1302
1303 PxeBc = &Private->PxeBc;
1304 Mode = PxeBc->Mode;
1305 Request = Private->Dhcp6Request;
1306 SrcPort = PXEBC_BS_DISCOVER_PORT;
1307 DestPort = PXEBC_BS_DISCOVER_PORT;
1308 OpFlags = 0;
1309
1310 if (!UseBis && Layer != NULL) {
1311 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
1312 }
1313
1314 if (Request == NULL) {
1315 return EFI_DEVICE_ERROR;
1316 }
1317
1318 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));
1319 if (Discover == NULL) {
1320 return EFI_OUT_OF_RESOURCES;
1321 }
1322
1323 //
1324 // Build the discover packet by the cached request packet before.
1325 //
1326 Xid = NET_RANDOM (NetRandomInitSeed ());
1327 Discover->TransactionId = HTONL (Xid);
1328 Discover->MessageType = Request->Dhcp6.Header.MessageType;
1329 RequestOpt = Request->Dhcp6.Option;
1330 DiscoverOpt = Discover->DhcpOptions;
1331 DiscoverLen = sizeof (EFI_DHCP6_HEADER);
1332 RequestLen = DiscoverLen;
1333
1334 while (RequestLen < Request->Length) {
1335 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);
1336 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen);
1337 if (OpCode != EFI_DHCP6_IA_TYPE_NA &&
1338 OpCode != EFI_DHCP6_IA_TYPE_TA) {
1339 //
1340 // Copy all the options except IA option.
1341 //
1342 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);
1343 DiscoverOpt += (OpLen + 4);
1344 DiscoverLen += (OpLen + 4);
1345 }
1346 RequestOpt += (OpLen + 4);
1347 RequestLen += (OpLen + 4);
1348 }
1349
1350 Status = PxeBc->UdpWrite (
1351 PxeBc,
1352 OpFlags,
1353 &Private->ServerIp,
1354 &DestPort,
1355 NULL,
1356 &Private->StationIp,
1357 &SrcPort,
1358 NULL,
1359 NULL,
1360 &DiscoverLen,
1361 (VOID *) Discover
1362 );
1363 if (EFI_ERROR (Status)) {
1364 return Status;
1365 }
1366
1367 //
1368 // Cache the right PXE reply packet here, set valid flag later.
1369 // Especially for PXE discover packet, store it into mode data here.
1370 //
1371 if (Private->IsDoDiscover) {
1372 CopyMem (&Mode->PxeDiscover.Dhcpv6, Discover, DiscoverLen);
1373 Reply = &Private->PxeReply.Dhcp6.Packet.Ack;
1374 } else {
1375 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;
1376 }
1377 ReadSize = (UINTN) Reply->Size;
1378
1379 Status = PxeBc->UdpRead (
1380 PxeBc,
1381 OpFlags,
1382 &Private->StationIp,
1383 &SrcPort,
1384 &Private->ServerIp,
1385 &DestPort,
1386 NULL,
1387 NULL,
1388 &ReadSize,
1389 (VOID *) &Reply->Dhcp6
1390 );
1391 if (EFI_ERROR (Status)) {
1392 return Status;
1393 }
1394
1395 return EFI_SUCCESS;
1396 }
1397
1398
1399 /**
1400 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1401
1402 @param[in] Private The pointer to PxeBc private data.
1403 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1404
1405 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1406 @retval Others Failed to finish the S.A.R.R. process.
1407
1408 **/
1409 EFI_STATUS
1410 PxeBcDhcp6Sarr (
1411 IN PXEBC_PRIVATE_DATA *Private,
1412 IN EFI_DHCP6_PROTOCOL *Dhcp6
1413 )
1414 {
1415 EFI_PXE_BASE_CODE_MODE *PxeMode;
1416 EFI_DHCP6_CONFIG_DATA Config;
1417 EFI_DHCP6_MODE_DATA Mode;
1418 EFI_DHCP6_RETRANSMISSION *Retransmit;
1419 EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM];
1420 UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE];
1421 UINT32 OptCount;
1422 EFI_STATUS Status;
1423
1424 Status = EFI_SUCCESS;
1425 PxeMode = Private->PxeBc.Mode;
1426
1427 //
1428 // Build option list for the request packet.
1429 //
1430 OptCount = PxeBcBuildDhcp6Options (Private, OptList, Buffer);
1431 ASSERT (OptCount> 0);
1432
1433 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));
1434 if (Retransmit == NULL) {
1435 return EFI_OUT_OF_RESOURCES;
1436 }
1437
1438 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));
1439 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));
1440
1441 Config.OptionCount = OptCount;
1442 Config.OptionList = OptList;
1443 Config.Dhcp6Callback = PxeBcDhcp6CallBack;
1444 Config.CallbackContext = Private;
1445 Config.IaInfoEvent = NULL;
1446 Config.RapidCommit = FALSE;
1447 Config.ReconfigureAccept = FALSE;
1448 Config.IaDescriptor.IaId = 1;
1449 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;
1450 Config.SolicitRetransmission = Retransmit;
1451 Retransmit->Irt = 4;
1452 Retransmit->Mrc = 4;
1453 Retransmit->Mrt = 32;
1454 Retransmit->Mrd = 60;
1455
1456 //
1457 // Configure the DHCPv6 instance for PXE boot.
1458 //
1459 Status = Dhcp6->Configure (Dhcp6, &Config);
1460 if (EFI_ERROR (Status)) {
1461 FreePool (Retransmit);
1462 return Status;
1463 }
1464
1465 //
1466 // Initialize the record fields for DHCPv6 offer in private data.
1467 //
1468 Private->IsProxyRecved = FALSE;
1469 Private->OfferNum = 0;
1470 Private->SelectIndex = 0;
1471 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
1472 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
1473
1474
1475 //
1476 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
1477 //
1478 Status = Dhcp6->Start (Dhcp6);
1479 if (EFI_ERROR (Status)) {
1480 if (Status == EFI_ICMP_ERROR) {
1481 PxeMode->IcmpErrorReceived = TRUE;
1482 }
1483 Dhcp6->Configure (Dhcp6, NULL);
1484 return Status;
1485 }
1486
1487 //
1488 // Get the acquired IPv6 address and store them.
1489 //
1490 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);
1491 if (EFI_ERROR (Status)) {
1492 Dhcp6->Stop (Dhcp6);
1493 return Status;
1494 }
1495
1496 ASSERT (Mode.Ia->State == Dhcp6Bound);
1497 CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
1498 CopyMem (&PxeMode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
1499
1500 Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);
1501 if (EFI_ERROR (Status)) {
1502 Dhcp6->Stop (Dhcp6);
1503 return Status;
1504 }
1505
1506 Status = PxeBcFlushStaionIp (Private, &Private->StationIp, NULL);
1507 if (EFI_ERROR (Status)) {
1508 PxeBcUnregisterIp6Address (Private);
1509 Dhcp6->Stop (Dhcp6);
1510 return Status;
1511 }
1512
1513 //
1514 // Check the selected offer whether BINL retry is needed.
1515 //
1516 Status = PxeBcHandleDhcp6Offer (Private);
1517 if (EFI_ERROR (Status)) {
1518 PxeBcUnregisterIp6Address (Private);
1519 Dhcp6->Stop (Dhcp6);
1520 return Status;
1521 }
1522
1523 AsciiPrint ("\n Station IP address is ");
1524
1525 PxeBcShowIp6Addr (&Private->StationIp.v6);
1526
1527 return EFI_SUCCESS;
1528 }
1529