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