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