]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c
1. Update PXE driver to support PXEv6 boot cross subnet.
[mirror_edk2.git] / NetworkPkg / UefiPxeBcDxe / PxeBcDhcp6.c
1 /** @file
2 Functions implementation related with DHCPv6 for UefiPxeBc Driver.
3
4 Copyright (c) 2009 - 2014, 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 // Well-known multi-cast address defined in section-24.1 of rfc-3315
20 //
21 // ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2
22 //
23 EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}};
24
25 /**
26 Parse out a DHCPv6 option by OptTag, and find the position in buffer.
27
28 @param[in] Buffer The pointer to the option buffer.
29 @param[in] Length Length of the option buffer.
30 @param[in] OptTag The required option tag.
31
32 @retval NULL Failed to parse the required option.
33 @retval Others The postion of the required option in buffer.
34
35 **/
36 EFI_DHCP6_PACKET_OPTION *
37 PxeBcParseDhcp6Options (
38 IN UINT8 *Buffer,
39 IN UINT32 Length,
40 IN UINT16 OptTag
41 )
42 {
43 EFI_DHCP6_PACKET_OPTION *Option;
44 UINT32 Offset;
45
46 Option = (EFI_DHCP6_PACKET_OPTION *) Buffer;
47 Offset = 0;
48
49 //
50 // OpLen and OpCode here are both stored in network order.
51 //
52 while (Offset < Length) {
53
54 if (NTOHS (Option->OpCode) == OptTag) {
55
56 return Option;
57 }
58
59 Offset += (NTOHS(Option->OpLen) + 4);
60 Option = (EFI_DHCP6_PACKET_OPTION *) (Buffer + Offset);
61 }
62
63 return NULL;
64 }
65
66
67 /**
68 Build the options buffer for the DHCPv6 request packet.
69
70 @param[in] Private The pointer to PxeBc private data.
71 @param[out] OptList The pointer to the option pointer array.
72 @param[in] Buffer The pointer to the buffer to contain the option list.
73
74 @return Index The count of the built-in options.
75
76 **/
77 UINT32
78 PxeBcBuildDhcp6Options (
79 IN PXEBC_PRIVATE_DATA *Private,
80 OUT EFI_DHCP6_PACKET_OPTION **OptList,
81 IN UINT8 *Buffer
82 )
83 {
84 PXEBC_DHCP6_OPTION_ENTRY OptEnt;
85 UINT32 Index;
86 UINT16 Value;
87
88 Index = 0;
89 OptList[0] = (EFI_DHCP6_PACKET_OPTION *) Buffer;
90
91 //
92 // Append client option request option
93 //
94 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ORO);
95 OptList[Index]->OpLen = HTONS (4);
96 OptEnt.Oro = (PXEBC_DHCP6_OPTION_ORO *) OptList[Index]->Data;
97 OptEnt.Oro->OpCode[0] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_URL);
98 OptEnt.Oro->OpCode[1] = HTONS(PXEBC_DHCP6_OPT_BOOT_FILE_PARAM);
99 Index++;
100 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
101
102 //
103 // Append client network device interface option
104 //
105 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_UNDI);
106 OptList[Index]->OpLen = HTONS ((UINT16)3);
107 OptEnt.Undi = (PXEBC_DHCP6_OPTION_UNDI *) OptList[Index]->Data;
108
109 if (Private->Nii != NULL) {
110 OptEnt.Undi->Type = Private->Nii->Type;
111 OptEnt.Undi->MajorVer = Private->Nii->MajorVer;
112 OptEnt.Undi->MinorVer = Private->Nii->MinorVer;
113 } else {
114 OptEnt.Undi->Type = DEFAULT_UNDI_TYPE;
115 OptEnt.Undi->MajorVer = DEFAULT_UNDI_MAJOR;
116 OptEnt.Undi->MinorVer = DEFAULT_UNDI_MINOR;
117 }
118
119 Index++;
120 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
121
122 //
123 // Append client system architecture option
124 //
125 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_ARCH);
126 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_ARCH));
127 OptEnt.Arch = (PXEBC_DHCP6_OPTION_ARCH *) OptList[Index]->Data;
128 Value = HTONS (EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE);
129 CopyMem (&OptEnt.Arch->Type, &Value, sizeof (UINT16));
130 Index++;
131 OptList[Index] = GET_NEXT_DHCP6_OPTION (OptList[Index - 1]);
132
133 //
134 // Append vendor class option to store the PXE class identifier.
135 //
136 OptList[Index]->OpCode = HTONS (PXEBC_DHCP6_OPT_VENDOR_CLASS);
137 OptList[Index]->OpLen = HTONS ((UINT16) sizeof (PXEBC_DHCP6_OPTION_VENDOR_CLASS));
138 OptEnt.VendorClass = (PXEBC_DHCP6_OPTION_VENDOR_CLASS *) OptList[Index]->Data;
139 OptEnt.VendorClass->Vendor = HTONL (PXEBC_DHCP6_ENTERPRISE_NUM);
140 OptEnt.VendorClass->ClassLen = HTONS ((UINT16) sizeof (PXEBC_CLASS_ID));
141 CopyMem (
142 &OptEnt.VendorClass->ClassId,
143 DEFAULT_CLASS_ID_DATA,
144 sizeof (PXEBC_CLASS_ID)
145 );
146 PxeBcUintnToAscDecWithFormat (
147 EFI_PXE_CLIENT_SYSTEM_ARCHITECTURE,
148 OptEnt.VendorClass->ClassId.ArchitectureType,
149 sizeof (OptEnt.VendorClass->ClassId.ArchitectureType)
150 );
151
152 if (Private->Nii != NULL) {
153 CopyMem (
154 OptEnt.VendorClass->ClassId.InterfaceName,
155 Private->Nii->StringId,
156 sizeof (OptEnt.VendorClass->ClassId.InterfaceName)
157 );
158 PxeBcUintnToAscDecWithFormat (
159 Private->Nii->MajorVer,
160 OptEnt.VendorClass->ClassId.UndiMajor,
161 sizeof (OptEnt.VendorClass->ClassId.UndiMajor)
162 );
163 PxeBcUintnToAscDecWithFormat (
164 Private->Nii->MinorVer,
165 OptEnt.VendorClass->ClassId.UndiMinor,
166 sizeof (OptEnt.VendorClass->ClassId.UndiMinor)
167 );
168 }
169
170 Index++;
171
172 return Index;
173 }
174
175
176 /**
177 Cache the DHCPv6 packet.
178
179 @param[in] Dst The pointer to the cache buffer for DHCPv6 packet.
180 @param[in] Src The pointer to the DHCPv6 packet to be cached.
181
182 **/
183 VOID
184 PxeBcCacheDhcp6Packet (
185 IN EFI_DHCP6_PACKET *Dst,
186 IN EFI_DHCP6_PACKET *Src
187 )
188 {
189 ASSERT (Dst->Size >= Src->Length);
190
191 CopyMem (&Dst->Dhcp6, &Src->Dhcp6, Src->Length);
192 Dst->Length = Src->Length;
193 }
194
195
196 /**
197 Free all the nodes in the list for boot file.
198
199 @param[in] Head The pointer to the head of list.
200
201 **/
202 VOID
203 PxeBcFreeBootFileOption (
204 IN LIST_ENTRY *Head
205 )
206 {
207 LIST_ENTRY *Entry;
208 LIST_ENTRY *NextEntry;
209 PXEBC_DHCP6_OPTION_NODE *Node;
210
211 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, Head) {
212 Node = NET_LIST_USER_STRUCT (Entry, PXEBC_DHCP6_OPTION_NODE, Link);
213 RemoveEntryList (Entry);
214 FreePool (Node);
215 }
216 }
217
218
219 /**
220 Parse the Boot File URL option.
221
222 @param[out] FileName The pointer to the boot file name.
223 @param[in, out] SrvAddr The pointer to the boot server address.
224 @param[in] BootFile The pointer to the boot file URL option data.
225 @param[in] Length The length of the boot file URL option data.
226
227 @retval EFI_ABORTED User cancel operation.
228 @retval EFI_SUCCESS Selected the boot menu successfully.
229 @retval EFI_NOT_READY Read the input key from the keybroad has not finish.
230
231 **/
232 EFI_STATUS
233 PxeBcExtractBootFileUrl (
234 OUT UINT8 **FileName,
235 IN OUT EFI_IPv6_ADDRESS *SrvAddr,
236 IN CHAR8 *BootFile,
237 IN UINT16 Length
238 )
239 {
240 UINT16 PrefixLen;
241 CHAR8 *BootFileNamePtr;
242 CHAR8 *BootFileName;
243 UINT16 BootFileNameLen;
244 CHAR8 *TmpStr;
245 CHAR8 TmpChar;
246 CHAR8 *ServerAddressOption;
247 CHAR8 *ServerAddress;
248 CHAR8 *ModeStr;
249 EFI_STATUS Status;
250
251 //
252 // The format of the Boot File URL option is:
253 //
254 // 0 1 2 3
255 // 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
256 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
257 // | OPT_BOOTFILE_URL | option-len |
258 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
259 // | |
260 // . bootfile-url (variable length) .
261 // | |
262 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
263 //
264
265 //
266 // Based upon RFC 5970 and UEFI 2.3 Errata D specification, bootfile-url format
267 // is tftp://[SERVER_ADDRESS]/BOOTFILE_NAME
268 // As an example where the BOOTFILE_NAME is the EFI loader and
269 // SERVER_ADDRESS is the ASCII encoding of an IPV6 address.
270 //
271 PrefixLen = (UINT16) AsciiStrLen (PXEBC_DHCP6_BOOT_FILE_URL_PREFIX);
272
273 if (Length <= PrefixLen ||
274 CompareMem (BootFile, PXEBC_DHCP6_BOOT_FILE_URL_PREFIX, PrefixLen) != 0) {
275 return EFI_NOT_FOUND;
276 }
277
278 BootFile = BootFile + PrefixLen;
279 Length = (UINT16) (Length - PrefixLen);
280
281 TmpStr = (CHAR8 *) AllocateZeroPool (Length + 1);
282 if (TmpStr == NULL) {
283 return EFI_OUT_OF_RESOURCES;
284 }
285
286 CopyMem (TmpStr, BootFile, Length);
287 TmpStr[Length] = '\0';
288
289 //
290 // Get the part of SERVER_ADDRESS string.
291 //
292 ServerAddressOption = TmpStr;
293 if (*ServerAddressOption != PXEBC_ADDR_START_DELIMITER) {
294 FreePool (TmpStr);
295 return EFI_INVALID_PARAMETER;
296 }
297
298 ServerAddressOption ++;
299 ServerAddress = ServerAddressOption;
300 while (*ServerAddress != '\0' && *ServerAddress != PXEBC_ADDR_END_DELIMITER) {
301 ServerAddress++;
302 }
303
304 if (*ServerAddress != PXEBC_ADDR_END_DELIMITER) {
305 FreePool (TmpStr);
306 return EFI_INVALID_PARAMETER;
307 }
308
309 *ServerAddress = '\0';
310
311 //
312 // Convert the string of server address to Ipv6 address format and store it.
313 //
314 Status = NetLibAsciiStrToIp6 (ServerAddressOption, SrvAddr);
315 if (EFI_ERROR (Status)) {
316 FreePool (TmpStr);
317 return Status;
318 }
319
320 //
321 // Get the part of BOOTFILE_NAME string.
322 //
323 BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1);
324 if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) {
325 FreePool (TmpStr);
326 return EFI_INVALID_PARAMETER;
327 }
328
329 ++BootFileNamePtr;
330 BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1);
331 if (BootFileNameLen != 0 || FileName != NULL) {
332 //
333 // Remove trailing mode=octet if present and ignore. All other modes are
334 // invalid for netboot6, so reject them.
335 //
336 ModeStr = AsciiStrStr (BootFileNamePtr, ";mode=octet");
337 if (ModeStr != NULL && *(ModeStr + AsciiStrLen (";mode=octet")) == '\0') {
338 *ModeStr = '\0';
339 } else if (AsciiStrStr (BootFileNamePtr, ";mode=") != NULL) {
340 return EFI_INVALID_PARAMETER;
341 }
342
343 //
344 // Extract boot file name from URL.
345 //
346 BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen);
347 if (BootFileName == NULL) {
348 FreePool (TmpStr);
349 return EFI_OUT_OF_RESOURCES;
350 }
351 *FileName = (UINT8*) BootFileName;
352
353 //
354 // Decode percent-encoding in boot file name.
355 //
356 while (*BootFileNamePtr != '\0') {
357 if (*BootFileNamePtr == '%') {
358 TmpChar = *(BootFileNamePtr+ 3);
359 *(BootFileNamePtr+ 3) = '\0';
360 *BootFileName = (UINT8) AsciiStrHexToUintn ((CHAR8*)(BootFileNamePtr + 1));
361 BootFileName++;
362 *(BootFileNamePtr+ 3) = TmpChar;
363 BootFileNamePtr += 3;
364 } else {
365 *BootFileName = *BootFileNamePtr;
366 BootFileName++;
367 BootFileNamePtr++;
368 }
369 }
370 *BootFileName = '\0';
371 }
372
373 FreePool (TmpStr);
374
375 return EFI_SUCCESS;
376 }
377
378
379 /**
380 Parse the Boot File Parameter option.
381
382 @param[in] BootFilePara The pointer to boot file parameter option data.
383 @param[out] BootFileSize The pointer to the parsed boot file size.
384
385 @retval EFI_SUCCESS Successfully obtained the boot file size from parameter option.
386 @retval EFI_NOT_FOUND Failed to extract the boot file size from parameter option.
387
388 **/
389 EFI_STATUS
390 PxeBcExtractBootFileParam (
391 IN CHAR8 *BootFilePara,
392 OUT UINT16 *BootFileSize
393 )
394 {
395 UINT16 Length;
396 UINT8 Index;
397 UINT8 Digit;
398 UINT32 Size;
399
400 CopyMem (&Length, BootFilePara, sizeof (UINT16));
401 Length = NTOHS (Length);
402
403 //
404 // The BootFile Size should be 1~5 byte ASCII strings
405 //
406 if (Length < 1 || Length > 5) {
407 return EFI_NOT_FOUND;
408 }
409
410 //
411 // Extract the value of BootFile Size.
412 //
413 BootFilePara = BootFilePara + sizeof (UINT16);
414 Size = 0;
415 for (Index = 0; Index < Length; Index++) {
416 if (EFI_ERROR (PxeBcUniHexToUint8 (&Digit, *(BootFilePara + Index)))) {
417 return EFI_NOT_FOUND;
418 }
419
420 Size = (Size + Digit) * 10;
421 }
422
423 Size = Size / 10;
424 if (Size > PXEBC_DHCP6_MAX_BOOT_FILE_SIZE) {
425 return EFI_NOT_FOUND;
426 }
427
428 *BootFileSize = (UINT16) Size;
429 return EFI_SUCCESS;
430 }
431
432
433 /**
434 Parse the cached DHCPv6 packet, including all the options.
435
436 @param[in] Cache6 The pointer to a cached DHCPv6 packet.
437
438 @retval EFI_SUCCESS Parsed the DHCPv6 packet successfully.
439 @retval EFI_DEVICE_ERROR Failed to parse and invalid the packet.
440
441 **/
442 EFI_STATUS
443 PxeBcParseDhcp6Packet (
444 IN PXEBC_DHCP6_PACKET_CACHE *Cache6
445 )
446 {
447 EFI_DHCP6_PACKET *Offer;
448 EFI_DHCP6_PACKET_OPTION **Options;
449 EFI_DHCP6_PACKET_OPTION *Option;
450 PXEBC_OFFER_TYPE OfferType;
451 BOOLEAN IsProxyOffer;
452 BOOLEAN IsPxeOffer;
453 UINT32 Offset;
454 UINT32 Length;
455 UINT32 EnterpriseNum;
456
457 IsProxyOffer = TRUE;
458 IsPxeOffer = FALSE;
459 Offer = &Cache6->Packet.Offer;
460 Options = Cache6->OptList;
461
462 ZeroMem (Cache6->OptList, sizeof (Cache6->OptList));
463
464 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option);
465 Offset = 0;
466 Length = GET_DHCP6_OPTION_SIZE (Offer);
467
468 //
469 // OpLen and OpCode here are both stored in network order, since they are from original packet.
470 //
471 while (Offset < Length) {
472
473 if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_IA_NA) {
474 Options[PXEBC_DHCP6_IDX_IA_NA] = Option;
475 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_URL) {
476 //
477 // The server sends this option to inform the client about an URL to a boot file.
478 //
479 Options[PXEBC_DHCP6_IDX_BOOT_FILE_URL] = Option;
480 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_BOOT_FILE_PARAM) {
481 Options[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] = Option;
482 } else if (NTOHS (Option->OpCode) == PXEBC_DHCP6_OPT_VENDOR_CLASS) {
483 Options[PXEBC_DHCP6_IDX_VENDOR_CLASS] = Option;
484 }
485
486 Offset += (NTOHS (Option->OpLen) + 4);
487 Option = (EFI_DHCP6_PACKET_OPTION *) (Offer->Dhcp6.Option + Offset);
488 }
489
490 //
491 // The offer with assigned client address is NOT a proxy offer.
492 // An ia_na option, embeded with valid ia_addr option and a status_code of success.
493 //
494 Option = Options[PXEBC_DHCP6_IDX_IA_NA];
495 if (Option != NULL) {
496 Option = PxeBcParseDhcp6Options (
497 Option->Data + 12,
498 NTOHS (Option->OpLen),
499 PXEBC_DHCP6_OPT_STATUS_CODE
500 );
501 if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) {
502 IsProxyOffer = FALSE;
503 }
504 }
505
506 //
507 // The offer with "PXEClient" is a pxe offer.
508 //
509 Option = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS];
510 EnterpriseNum = HTONL(PXEBC_DHCP6_ENTERPRISE_NUM);
511
512 if (Option != NULL &&
513 NTOHS(Option->OpLen) >= 13 &&
514 CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 &&
515 CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0) {
516 IsPxeOffer = TRUE;
517 }
518
519 //
520 // Determine offer type of the dhcp6 packet.
521 //
522 if (IsPxeOffer) {
523 //
524 // It's a binl offer only with PXEClient.
525 //
526 OfferType = IsProxyOffer ? PxeOfferTypeProxyBinl : PxeOfferTypeDhcpBinl;
527 } else {
528 //
529 // It's a dhcp only offer, which is a pure dhcp6 offer packet.
530 //
531 OfferType = PxeOfferTypeDhcpOnly;
532 }
533
534 Cache6->OfferType = OfferType;
535
536 return EFI_SUCCESS;
537 }
538
539
540 /**
541 Cache the DHCPv6 ack packet, and parse it on demand.
542
543 @param[in] Private The pointer to PxeBc private data.
544 @param[in] Ack The pointer to the DHCPv6 ack packet.
545 @param[in] Verified If TRUE, parse the ACK packet and store info into mode data.
546
547 **/
548 VOID
549 PxeBcCopyDhcp6Ack (
550 IN PXEBC_PRIVATE_DATA *Private,
551 IN EFI_DHCP6_PACKET *Ack,
552 IN BOOLEAN Verified
553 )
554 {
555 EFI_PXE_BASE_CODE_MODE *Mode;
556
557 Mode = Private->PxeBc.Mode;
558
559 PxeBcCacheDhcp6Packet (&Private->DhcpAck.Dhcp6.Packet.Ack, Ack);
560
561 if (Verified) {
562 //
563 // Parse the ack packet and store it into mode data if needed.
564 //
565 PxeBcParseDhcp6Packet (&Private->DhcpAck.Dhcp6);
566 CopyMem (&Mode->DhcpAck.Dhcpv6, &Ack->Dhcp6, Ack->Length);
567 Mode->DhcpAckReceived = TRUE;
568 }
569 }
570
571
572 /**
573 Cache the DHCPv6 proxy offer packet according to the received order.
574
575 @param[in] Private The pointer to PxeBc private data.
576 @param[in] OfferIndex The received order of offer packets.
577
578 **/
579 VOID
580 PxeBcCopyDhcp6Proxy (
581 IN PXEBC_PRIVATE_DATA *Private,
582 IN UINT32 OfferIndex
583 )
584 {
585 EFI_PXE_BASE_CODE_MODE *Mode;
586 EFI_DHCP6_PACKET *Offer;
587
588 ASSERT (OfferIndex < Private->OfferNum);
589 ASSERT (OfferIndex < PXEBC_OFFER_MAX_NUM);
590
591 Mode = Private->PxeBc.Mode;
592 Offer = &Private->OfferBuffer[OfferIndex].Dhcp6.Packet.Offer;
593
594 //
595 // Cache the proxy offer packet and parse it.
596 //
597 PxeBcCacheDhcp6Packet (&Private->ProxyOffer.Dhcp6.Packet.Offer, Offer);
598 PxeBcParseDhcp6Packet (&Private->ProxyOffer.Dhcp6);
599
600 //
601 // Store this packet into mode data.
602 //
603 CopyMem (&Mode->ProxyOffer.Dhcpv6, &Offer->Dhcp6, Offer->Length);
604 Mode->ProxyOfferReceived = TRUE;
605 }
606
607 /**
608 Seek the address of the first byte of the option header.
609
610 @param[in] Buf The pointer to the buffer.
611 @param[in] SeekLen The length to seek.
612 @param[in] OptType The option type.
613
614 @retval NULL If it failed to seek the option.
615 @retval others The position to the option.
616
617 **/
618 UINT8 *
619 PxeBcDhcp6SeekOption (
620 IN UINT8 *Buf,
621 IN UINT32 SeekLen,
622 IN UINT16 OptType
623 )
624 {
625 UINT8 *Cursor;
626 UINT8 *Option;
627 UINT16 DataLen;
628 UINT16 OpCode;
629
630 Option = NULL;
631 Cursor = Buf;
632
633 while (Cursor < Buf + SeekLen) {
634 OpCode = ReadUnaligned16 ((UINT16 *) Cursor);
635 if (OpCode == HTONS (OptType)) {
636 Option = Cursor;
637 break;
638 }
639 DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2)));
640 Cursor += (DataLen + 4);
641 }
642
643 return Option;
644 }
645
646
647 /**
648 Build and send out the request packet for the bootfile, and parse the reply.
649
650 @param[in] Private The pointer to PxeBc private data.
651 @param[in] Index PxeBc option boot item type.
652
653 @retval EFI_SUCCESS Successfully discovered the boot file.
654 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
655 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
656 @retval Others Failed to discover the boot file.
657
658 **/
659 EFI_STATUS
660 PxeBcRequestBootService (
661 IN PXEBC_PRIVATE_DATA *Private,
662 IN UINT32 Index
663 )
664 {
665 EFI_PXE_BASE_CODE_UDP_PORT SrcPort;
666 EFI_PXE_BASE_CODE_UDP_PORT DestPort;
667 EFI_PXE_BASE_CODE_MODE *Mode;
668 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
669 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover;
670 UINTN DiscoverLen;
671 EFI_DHCP6_PACKET *Request;
672 UINTN RequestLen;
673 EFI_DHCP6_PACKET *Reply;
674 UINT8 *RequestOpt;
675 UINT8 *DiscoverOpt;
676 UINTN ReadSize;
677 UINT16 OpFlags;
678 UINT16 OpCode;
679 UINT16 OpLen;
680 EFI_STATUS Status;
681 EFI_DHCP6_PACKET *ProxyOffer;
682 UINT8 *Option;
683
684 PxeBc = &Private->PxeBc;
685 Mode = PxeBc->Mode;
686 Request = Private->Dhcp6Request;
687 ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer;
688 SrcPort = PXEBC_BS_DISCOVER_PORT;
689 DestPort = PXEBC_BS_DISCOVER_PORT;
690 OpFlags = 0;
691
692 if (Request == NULL) {
693 return EFI_DEVICE_ERROR;
694 }
695
696 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));
697 if (Discover == NULL) {
698 return EFI_OUT_OF_RESOURCES;
699 }
700
701 //
702 // Build the request packet by the cached request packet before.
703 //
704 Discover->TransactionId = ProxyOffer->Dhcp6.Header.TransactionId;
705 Discover->MessageType = Request->Dhcp6.Header.MessageType;
706 RequestOpt = Request->Dhcp6.Option;
707 DiscoverOpt = Discover->DhcpOptions;
708 DiscoverLen = sizeof (EFI_DHCP6_HEADER);
709 RequestLen = DiscoverLen;
710
711 //
712 // Find Server ID Option from ProxyOffer.
713 //
714 Option = PxeBcDhcp6SeekOption (
715 ProxyOffer->Dhcp6.Option,
716 ProxyOffer->Length - 4,
717 PXEBC_DHCP6_OPT_SERVER_ID
718 );
719 if (Option == NULL) {
720 return EFI_NOT_FOUND;
721 }
722
723 //
724 // Add Server ID Option.
725 //
726 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen);
727 CopyMem (DiscoverOpt, Option, OpLen + 4);
728 DiscoverOpt += (OpLen + 4);
729 DiscoverLen += (OpLen + 4);
730
731 while (RequestLen < Request->Length) {
732 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);
733 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen);
734 if (OpCode != EFI_DHCP6_IA_TYPE_NA &&
735 OpCode != EFI_DHCP6_IA_TYPE_TA &&
736 OpCode != PXEBC_DHCP6_OPT_SERVER_ID
737 ) {
738 //
739 // Copy all the options except IA option and Server ID
740 //
741 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);
742 DiscoverOpt += (OpLen + 4);
743 DiscoverLen += (OpLen + 4);
744 }
745 RequestOpt += (OpLen + 4);
746 RequestLen += (OpLen + 4);
747 }
748
749 //
750 // Update Elapsed option in the package
751 //
752 Option = PxeBcDhcp6SeekOption (
753 Discover->DhcpOptions,
754 (UINT32)(RequestLen - 4),
755 PXEBC_DHCP6_OPT_ELAPSED_TIME
756 );
757 if (Option != NULL) {
758 CalcElapsedTime (Private);
759 WriteUnaligned16 ((UINT16*)(Option + 4), HTONS((UINT16) Private->ElapsedTime));
760 }
761
762 Status = PxeBc->UdpWrite (
763 PxeBc,
764 OpFlags,
765 &Private->ServerIp,
766 &DestPort,
767 NULL,
768 &Private->StationIp,
769 &SrcPort,
770 NULL,
771 NULL,
772 &DiscoverLen,
773 (VOID *) Discover
774 );
775
776 if (EFI_ERROR (Status)) {
777 return Status;
778 }
779
780 //
781 // Cache the right PXE reply packet here, set valid flag later.
782 // Especially for PXE discover packet, store it into mode data here.
783 //
784 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;
785 ReadSize = (UINTN) Reply->Size;
786
787 //
788 // Start Udp6Read instance
789 //
790 Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
791 if (EFI_ERROR (Status)) {
792 return Status;
793 }
794
795 Status = PxeBc->UdpRead (
796 PxeBc,
797 EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP,
798 &Private->StationIp,
799 &SrcPort,
800 &Private->ServerIp,
801 &DestPort,
802 NULL,
803 NULL,
804 &ReadSize,
805 (VOID *) &Reply->Dhcp6
806 );
807 //
808 // Stop Udp6Read instance
809 //
810 Private->Udp6Read->Configure (Private->Udp6Read, NULL);
811
812 if (EFI_ERROR (Status)) {
813 return Status;
814 }
815
816 //
817 // Update length
818 //
819 Reply->Length = (UINT32) ReadSize;
820
821 return EFI_SUCCESS;
822 }
823
824
825 /**
826 Retry to request bootfile name by the BINL offer.
827
828 @param[in] Private The pointer to PxeBc private data.
829 @param[in] Index The received order of offer packets.
830
831 @retval EFI_SUCCESS Successfully retried a request for the bootfile name.
832 @retval EFI_DEVICE_ERROR Failed to retry the bootfile name.
833
834 **/
835 EFI_STATUS
836 PxeBcRetryDhcp6Binl (
837 IN PXEBC_PRIVATE_DATA *Private,
838 IN UINT32 Index
839 )
840 {
841 EFI_PXE_BASE_CODE_MODE *Mode;
842 PXEBC_DHCP6_PACKET_CACHE *Offer;
843 PXEBC_DHCP6_PACKET_CACHE *Cache6;
844 EFI_STATUS Status;
845
846 ASSERT (Index < PXEBC_OFFER_MAX_NUM);
847 ASSERT (Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeDhcpBinl ||
848 Private->OfferBuffer[Index].Dhcp6.OfferType == PxeOfferTypeProxyBinl);
849
850 Mode = Private->PxeBc.Mode;
851 Private->IsDoDiscover = FALSE;
852 Offer = &Private->OfferBuffer[Index].Dhcp6;
853 if (Offer->OfferType == PxeOfferTypeDhcpBinl) {
854 //
855 // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead.
856 //
857 CopyMem (
858 &Private->ServerIp.v6,
859 &mAllDhcpRelayAndServersAddress,
860 sizeof (EFI_IPv6_ADDRESS)
861 );
862 } else {
863 ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
864 //
865 // Parse out the next server address from the last offer, and store it
866 //
867 Status = PxeBcExtractBootFileUrl (
868 &Private->BootFileName,
869 &Private->ServerIp.v6,
870 (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data),
871 NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen)
872 );
873 if (EFI_ERROR (Status)) {
874 return Status;
875 }
876 }
877
878 //
879 // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer.
880 //
881 Status = PxeBcRequestBootService (Private, Index);
882
883 if (EFI_ERROR (Status)) {
884 return Status;
885 }
886
887 Cache6 = &Private->ProxyOffer.Dhcp6;
888 Status = PxeBcParseDhcp6Packet (Cache6);
889 if (EFI_ERROR (Status)) {
890 return Status;
891 }
892
893 if (Cache6->OfferType != PxeOfferTypeProxyPxe10 &&
894 Cache6->OfferType != PxeOfferTypeProxyWfm11a &&
895 Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
896 //
897 // This BINL ack doesn't have discovery option set or multicast option set
898 // or bootfile name specified.
899 //
900 return EFI_DEVICE_ERROR;
901 }
902
903 Mode->ProxyOfferReceived = TRUE;
904 CopyMem (
905 &Mode->ProxyOffer.Dhcpv6,
906 &Cache6->Packet.Offer.Dhcp6,
907 Cache6->Packet.Offer.Length
908 );
909
910 return EFI_SUCCESS;
911 }
912
913
914 /**
915 Cache all the received DHCPv6 offers, and set OfferIndex and OfferCount.
916
917 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
918 @param[in] RcvdOffer The pointer to the received offer packet.
919
920 **/
921 VOID
922 PxeBcCacheDhcp6Offer (
923 IN PXEBC_PRIVATE_DATA *Private,
924 IN EFI_DHCP6_PACKET *RcvdOffer
925 )
926 {
927 PXEBC_DHCP6_PACKET_CACHE *Cache6;
928 EFI_DHCP6_PACKET *Offer;
929 PXEBC_OFFER_TYPE OfferType;
930
931 Cache6 = &Private->OfferBuffer[Private->OfferNum].Dhcp6;
932 Offer = &Cache6->Packet.Offer;
933
934 //
935 // Cache the content of DHCPv6 packet firstly.
936 //
937 PxeBcCacheDhcp6Packet (Offer, RcvdOffer);
938
939 //
940 // Validate the DHCPv6 packet, and parse the options and offer type.
941 //
942 if (EFI_ERROR (PxeBcParseDhcp6Packet (Cache6))) {
943 return ;
944 }
945
946 //
947 // Determine whether cache the current offer by type, and record OfferIndex and OfferCount.
948 //
949 OfferType = Cache6->OfferType;
950 ASSERT (OfferType < PxeOfferTypeMax);
951 ASSERT (Private->OfferCount[OfferType] < PXEBC_OFFER_MAX_NUM);
952
953 if (IS_PROXY_OFFER (OfferType)) {
954 //
955 // It's a proxy offer without yiaddr, including PXE10, WFM11a or BINL offer.
956 //
957 Private->IsProxyRecved = TRUE;
958
959 if (OfferType == PxeOfferTypeProxyBinl) {
960 //
961 // Cache all proxy BINL offers.
962 //
963 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
964 Private->OfferCount[OfferType]++;
965 } else if (Private->OfferCount[OfferType] > 0) {
966 //
967 // Only cache the first PXE10/WFM11a offer, and discard the others.
968 //
969 Private->OfferIndex[OfferType][0] = Private->OfferNum;
970 Private->OfferCount[OfferType] = 1;
971 } else {
972 return;
973 }
974 } else {
975 //
976 // It's a DHCPv6 offer with yiaddr, and cache them all.
977 //
978 Private->OfferIndex[OfferType][Private->OfferCount[OfferType]] = Private->OfferNum;
979 Private->OfferCount[OfferType]++;
980 }
981
982 Private->OfferNum++;
983 }
984
985
986 /**
987 Select an DHCPv6 offer, and record SelectIndex and SelectProxyType.
988
989 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
990
991 **/
992 VOID
993 PxeBcSelectDhcp6Offer (
994 IN PXEBC_PRIVATE_DATA *Private
995 )
996 {
997 UINT32 Index;
998 UINT32 OfferIndex;
999 PXEBC_OFFER_TYPE OfferType;
1000
1001 Private->SelectIndex = 0;
1002
1003 if (Private->IsOfferSorted) {
1004 //
1005 // Select offer by default policy.
1006 //
1007 if (Private->OfferCount[PxeOfferTypeDhcpPxe10] > 0) {
1008 //
1009 // 1. DhcpPxe10 offer
1010 //
1011 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpPxe10][0] + 1;
1012
1013 } else if (Private->OfferCount[PxeOfferTypeDhcpWfm11a] > 0) {
1014 //
1015 // 2. DhcpWfm11a offer
1016 //
1017 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpWfm11a][0] + 1;
1018
1019 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
1020 Private->OfferCount[PxeOfferTypeProxyPxe10] > 0) {
1021 //
1022 // 3. DhcpOnly offer and ProxyPxe10 offer.
1023 //
1024 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
1025 Private->SelectProxyType = PxeOfferTypeProxyPxe10;
1026
1027 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
1028 Private->OfferCount[PxeOfferTypeProxyWfm11a] > 0) {
1029 //
1030 // 4. DhcpOnly offer and ProxyWfm11a offer.
1031 //
1032 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
1033 Private->SelectProxyType = PxeOfferTypeProxyWfm11a;
1034
1035 } else if (Private->OfferCount[PxeOfferTypeDhcpBinl] > 0) {
1036 //
1037 // 5. DhcpBinl offer.
1038 //
1039 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpBinl][0] + 1;
1040
1041 } else if (Private->OfferCount[PxeOfferTypeDhcpOnly] > 0 &&
1042 Private->OfferCount[PxeOfferTypeProxyBinl] > 0) {
1043 //
1044 // 6. DhcpOnly offer and ProxyBinl offer.
1045 //
1046 Private->SelectIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][0] + 1;
1047 Private->SelectProxyType = PxeOfferTypeProxyBinl;
1048
1049 } else {
1050 //
1051 // 7. DhcpOnly offer with bootfilename.
1052 //
1053 for (Index = 0; Index < Private->OfferCount[PxeOfferTypeDhcpOnly]; Index++) {
1054 OfferIndex = Private->OfferIndex[PxeOfferTypeDhcpOnly][Index];
1055 if (Private->OfferBuffer[OfferIndex].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL) {
1056 Private->SelectIndex = OfferIndex + 1;
1057 break;
1058 }
1059 }
1060 }
1061 } else {
1062 //
1063 // Select offer by received order.
1064 //
1065 for (Index = 0; Index < Private->OfferNum; Index++) {
1066
1067 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;
1068
1069 if (IS_PROXY_OFFER (OfferType)) {
1070 //
1071 // Skip proxy offers
1072 //
1073 continue;
1074 }
1075
1076 if (!Private->IsProxyRecved &&
1077 OfferType == PxeOfferTypeDhcpOnly &&
1078 Private->OfferBuffer[Index].Dhcp6.OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] == NULL) {
1079 //
1080 // Skip if DhcpOnly offer without any other proxy offers or bootfilename.
1081 //
1082 continue;
1083 }
1084
1085 Private->SelectIndex = Index + 1;
1086 break;
1087 }
1088 }
1089 }
1090
1091
1092 /**
1093 Handle the DHCPv6 offer packet.
1094
1095 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1096
1097 @retval EFI_SUCCESS Handled the DHCPv6 offer packet successfully.
1098 @retval EFI_NO_RESPONSE No response to the following request packet.
1099
1100 **/
1101 EFI_STATUS
1102 PxeBcHandleDhcp6Offer (
1103 IN PXEBC_PRIVATE_DATA *Private
1104 )
1105 {
1106 PXEBC_DHCP6_PACKET_CACHE *Cache6;
1107 EFI_STATUS Status;
1108 PXEBC_OFFER_TYPE OfferType;
1109 UINT32 ProxyIndex;
1110 UINT32 SelectIndex;
1111 UINT32 Index;
1112
1113 ASSERT (Private->SelectIndex > 0);
1114 SelectIndex = (UINT32) (Private->SelectIndex - 1);
1115 ASSERT (SelectIndex < PXEBC_OFFER_MAX_NUM);
1116 Cache6 = &Private->OfferBuffer[SelectIndex].Dhcp6;
1117 Status = EFI_SUCCESS;
1118
1119 if (Cache6->OfferType == PxeOfferTypeDhcpBinl) {
1120 //
1121 // DhcpBinl offer is selected, so need try to request bootfilename by this offer.
1122 //
1123 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, SelectIndex))) {
1124 Status = EFI_NO_RESPONSE;
1125 }
1126 } else if (Cache6->OfferType == PxeOfferTypeDhcpOnly) {
1127
1128 if (Private->IsProxyRecved) {
1129 //
1130 // DhcpOnly offer is selected, so need try to request bootfilename.
1131 //
1132 ProxyIndex = 0;
1133 if (Private->IsOfferSorted) {
1134 //
1135 // The proxy offer should be determined if select by default policy.
1136 // IsOfferSorted means all offers are labeled by OfferIndex.
1137 //
1138 ASSERT (Private->OfferCount[Private->SelectProxyType] > 0);
1139
1140 if (Private->SelectProxyType == PxeOfferTypeProxyBinl) {
1141 //
1142 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1143 //
1144 for (Index = 0; Index < Private->OfferCount[Private->SelectProxyType]; Index++) {
1145
1146 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][Index];
1147 if (!EFI_ERROR (PxeBcRetryDhcp6Binl (Private, ProxyIndex))) {
1148 break;
1149 }
1150 }
1151 if (Index == Private->OfferCount[Private->SelectProxyType]) {
1152 Status = EFI_NO_RESPONSE;
1153 }
1154 } else {
1155 //
1156 // For other proxy offers (pxe10 or wfm11a), only one is buffered.
1157 //
1158 ProxyIndex = Private->OfferIndex[Private->SelectProxyType][0];
1159 }
1160 } else {
1161 //
1162 // The proxy offer should not be determined if select by received order.
1163 //
1164 Status = EFI_NO_RESPONSE;
1165
1166 for (Index = 0; Index < Private->OfferNum; Index++) {
1167
1168 OfferType = Private->OfferBuffer[Index].Dhcp6.OfferType;
1169
1170 if (!IS_PROXY_OFFER (OfferType)) {
1171 //
1172 // Skip non proxy dhcp offers.
1173 //
1174 continue;
1175 }
1176
1177 if (OfferType == PxeOfferTypeProxyBinl) {
1178 //
1179 // Try all the cached ProxyBinl offer one by one to request bootfilename.
1180 //
1181 if (EFI_ERROR (PxeBcRetryDhcp6Binl (Private, Index))) {
1182 continue;
1183 }
1184 }
1185
1186 Private->SelectProxyType = OfferType;
1187 ProxyIndex = Index;
1188 Status = EFI_SUCCESS;
1189 break;
1190 }
1191 }
1192
1193 if (!EFI_ERROR (Status) && Private->SelectProxyType != PxeOfferTypeProxyBinl) {
1194 //
1195 // Success to try to request by a ProxyPxe10 or ProxyWfm11a offer, copy and parse it.
1196 //
1197 PxeBcCopyDhcp6Proxy (Private, ProxyIndex);
1198 }
1199 } else {
1200 //
1201 // Othewise, the bootfilename must be included in DhcpOnly offer.
1202 //
1203 ASSERT (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL);
1204 }
1205 }
1206
1207 if (!EFI_ERROR (Status)) {
1208 //
1209 // All PXE boot information is ready by now.
1210 //
1211 PxeBcCopyDhcp6Ack (Private, &Private->DhcpAck.Dhcp6.Packet.Ack, TRUE);
1212 Private->PxeBc.Mode->DhcpDiscoverValid = TRUE;
1213 }
1214
1215 return Status;
1216 }
1217
1218
1219 /**
1220 Unregister the address by Ip6Config protocol.
1221
1222 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1223
1224 **/
1225 VOID
1226 PxeBcUnregisterIp6Address (
1227 IN PXEBC_PRIVATE_DATA *Private
1228 )
1229 {
1230 if (Private->Ip6Policy != PXEBC_IP6_POLICY_MAX) {
1231 //
1232 // PXE driver change the policy of IP6 driver, it's a chance to recover.
1233 // Keep the point and there is no enough requirements to do recovery.
1234 //
1235 }
1236 }
1237
1238 /**
1239 Check whether IP driver could route the message which will be sent to ServerIp address.
1240
1241 This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
1242 route is found in IP6 route table, the address will be filed in GatewayAddr and return.
1243
1244 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1245 @param[in] TimeOutInSecond Timeout value in seconds.
1246 @param[out] GatewayAddr Pointer to store the gateway IP address.
1247
1248 @retval EFI_SUCCESS Found a valid gateway address successfully.
1249 @retval EFI_TIMEOUT The operation is time out.
1250 @retval Other Unexpect error happened.
1251
1252 **/
1253 EFI_STATUS
1254 PxeBcCheckRouteTable (
1255 IN PXEBC_PRIVATE_DATA *Private,
1256 IN UINTN TimeOutInSecond,
1257 OUT EFI_IPv6_ADDRESS *GatewayAddr
1258 )
1259 {
1260 EFI_STATUS Status;
1261 EFI_IP6_PROTOCOL *Ip6;
1262 EFI_IP6_MODE_DATA Ip6ModeData;
1263 UINTN Index;
1264 EFI_EVENT TimeOutEvt;
1265 UINTN RetryCount;
1266 BOOLEAN GatewayIsFound;
1267
1268 ASSERT (GatewayAddr != NULL);
1269 ASSERT (Private != NULL);
1270
1271 Ip6 = Private->Ip6;
1272 GatewayIsFound = FALSE;
1273 RetryCount = 0;
1274 TimeOutEvt = NULL;
1275 ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));
1276
1277 while (TRUE) {
1278 Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);
1279 if (EFI_ERROR (Status)) {
1280 goto ON_EXIT;
1281 }
1282
1283 //
1284 // Find out the gateway address which can route the message whcih send to ServerIp.
1285 //
1286 for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {
1287 if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {
1288 IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);
1289 GatewayIsFound = TRUE;
1290 break;
1291 }
1292 }
1293
1294 if (Ip6ModeData.AddressList != NULL) {
1295 FreePool (Ip6ModeData.AddressList);
1296 }
1297 if (Ip6ModeData.GroupTable != NULL) {
1298 FreePool (Ip6ModeData.GroupTable);
1299 }
1300 if (Ip6ModeData.RouteTable != NULL) {
1301 FreePool (Ip6ModeData.RouteTable);
1302 }
1303 if (Ip6ModeData.NeighborCache != NULL) {
1304 FreePool (Ip6ModeData.NeighborCache);
1305 }
1306 if (Ip6ModeData.PrefixTable != NULL) {
1307 FreePool (Ip6ModeData.PrefixTable);
1308 }
1309 if (Ip6ModeData.IcmpTypeList != NULL) {
1310 FreePool (Ip6ModeData.IcmpTypeList);
1311 }
1312
1313 if (GatewayIsFound || RetryCount == TimeOutInSecond) {
1314 break;
1315 }
1316
1317 RetryCount++;
1318
1319 //
1320 // Delay 1 second then recheck it again.
1321 //
1322 if (TimeOutEvt == NULL) {
1323 Status = gBS->CreateEvent (
1324 EVT_TIMER,
1325 TPL_CALLBACK,
1326 NULL,
1327 NULL,
1328 &TimeOutEvt
1329 );
1330 if (EFI_ERROR (Status)) {
1331 goto ON_EXIT;
1332 }
1333 }
1334
1335 Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);
1336 if (EFI_ERROR (Status)) {
1337 goto ON_EXIT;
1338 }
1339 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
1340 Ip6->Poll (Ip6);
1341 }
1342 }
1343
1344 ON_EXIT:
1345 if (TimeOutEvt != NULL) {
1346 gBS->CloseEvent (TimeOutEvt);
1347 }
1348
1349 if (GatewayIsFound) {
1350 Status = EFI_SUCCESS;
1351 } else if (RetryCount == TimeOutInSecond) {
1352 Status = EFI_TIMEOUT;
1353 }
1354
1355 return Status;
1356 }
1357
1358 /**
1359 Register the ready station address and gateway by Ip6Config protocol.
1360
1361 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1362 @param[in] Address The pointer to the ready address.
1363
1364 @retval EFI_SUCCESS Registered the address succesfully.
1365 @retval Others Failed to register the address.
1366
1367 **/
1368 EFI_STATUS
1369 PxeBcRegisterIp6Address (
1370 IN PXEBC_PRIVATE_DATA *Private,
1371 IN EFI_IPv6_ADDRESS *Address
1372 )
1373 {
1374 EFI_IP6_PROTOCOL *Ip6;
1375 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
1376 EFI_IP6_CONFIG_POLICY Policy;
1377 EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;
1378 EFI_IPv6_ADDRESS GatewayAddr;
1379 UINTN DataSize;
1380 EFI_EVENT TimeOutEvt;
1381 EFI_EVENT MappedEvt;
1382 EFI_STATUS Status;
1383 UINT64 DadTriggerTime;
1384 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
1385
1386 Status = EFI_SUCCESS;
1387 TimeOutEvt = NULL;
1388 MappedEvt = NULL;
1389 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
1390 Ip6Cfg = Private->Ip6Cfg;
1391 Ip6 = Private->Ip6;
1392
1393 ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
1394 CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS));
1395
1396 Status = Ip6->Configure (Ip6, &Private->Ip6CfgData);
1397 if (EFI_ERROR (Status)) {
1398 goto ON_EXIT;
1399 }
1400
1401 //
1402 // Retrieve the gateway address from IP6 route table.
1403 //
1404 Status = PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);
1405 if (EFI_ERROR (Status)) {
1406 goto ON_EXIT;
1407 }
1408
1409 //
1410 // There is no channel between IP6 and PXE driver about address setting,
1411 // so it has to set the new address by Ip6ConfigProtocol manually.
1412 //
1413 Policy = Ip6ConfigPolicyManual;
1414 Status = Ip6Cfg->SetData (
1415 Ip6Cfg,
1416 Ip6ConfigDataTypePolicy,
1417 sizeof(EFI_IP6_CONFIG_POLICY),
1418 &Policy
1419 );
1420 if (EFI_ERROR (Status)) {
1421 //
1422 // There is no need to recover later.
1423 //
1424 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;
1425 goto ON_EXIT;
1426 }
1427
1428 //
1429 // Get Duplicate Address Detection Transmits count.
1430 //
1431 DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
1432 Status = Ip6Cfg->GetData (
1433 Ip6Cfg,
1434 Ip6ConfigDataTypeDupAddrDetectTransmits,
1435 &DataSize,
1436 &DadXmits
1437 );
1438 if (EFI_ERROR (Status)) {
1439 goto ON_EXIT;
1440 }
1441
1442 //
1443 // Create a timer as setting address timeout event since DAD in IP6 driver.
1444 //
1445 Status = gBS->CreateEvent (
1446 EVT_TIMER,
1447 TPL_CALLBACK,
1448 NULL,
1449 NULL,
1450 &TimeOutEvt
1451 );
1452 if (EFI_ERROR (Status)) {
1453 goto ON_EXIT;
1454 }
1455
1456 //
1457 // Create a notify event to set address flag when DAD if IP6 driver succeeded.
1458 //
1459 Status = gBS->CreateEvent (
1460 EVT_NOTIFY_SIGNAL,
1461 TPL_NOTIFY,
1462 PxeBcCommonNotify,
1463 &Private->IsAddressOk,
1464 &MappedEvt
1465 );
1466 if (EFI_ERROR (Status)) {
1467 goto ON_EXIT;
1468 }
1469
1470 Status = Ip6Cfg->RegisterDataNotify (
1471 Ip6Cfg,
1472 Ip6ConfigDataTypeManualAddress,
1473 MappedEvt
1474 );
1475 if (EFI_ERROR(Status)) {
1476 goto ON_EXIT;
1477 }
1478
1479 Status = Ip6Cfg->SetData (
1480 Ip6Cfg,
1481 Ip6ConfigDataTypeManualAddress,
1482 sizeof(EFI_IP6_CONFIG_MANUAL_ADDRESS),
1483 &CfgAddr
1484 );
1485 if (EFI_ERROR(Status) && Status != EFI_NOT_READY) {
1486 goto ON_EXIT;
1487 }
1488
1489 //
1490 // Start the 5 secondes timer to wait for setting address.
1491 //
1492 Status = EFI_NO_MAPPING;
1493 DadTriggerTime = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;
1494 gBS->SetTimer (TimeOutEvt, TimerRelative, DadTriggerTime);
1495
1496 while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
1497 Ip6->Poll (Ip6);
1498 if (Private->IsAddressOk) {
1499 Status = EFI_SUCCESS;
1500 break;
1501 }
1502 }
1503
1504 //
1505 // Set the default gateway address back if needed.
1506 //
1507 if (!NetIp6IsUnspecifiedAddr (&GatewayAddr)) {
1508 Status = Ip6Cfg->SetData (
1509 Ip6Cfg,
1510 Ip6ConfigDataTypeGateway,
1511 sizeof (EFI_IPv6_ADDRESS),
1512 &GatewayAddr
1513 );
1514 if (EFI_ERROR (Status)) {
1515 goto ON_EXIT;
1516 }
1517 }
1518
1519 ON_EXIT:
1520 if (MappedEvt != NULL) {
1521 Ip6Cfg->UnregisterDataNotify (
1522 Ip6Cfg,
1523 Ip6ConfigDataTypeManualAddress,
1524 MappedEvt
1525 );
1526 gBS->CloseEvent (MappedEvt);
1527 }
1528 if (TimeOutEvt != NULL) {
1529 gBS->CloseEvent (TimeOutEvt);
1530 }
1531 return Status;
1532 }
1533
1534 /**
1535 Set the IP6 policy to Automatic.
1536
1537 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1538
1539 @retval EFI_SUCCESS Switch the IP policy succesfully.
1540 @retval Others Unexpect error happened.
1541
1542 **/
1543 EFI_STATUS
1544 PxeBcSetIp6Policy (
1545 IN PXEBC_PRIVATE_DATA *Private
1546 )
1547 {
1548 EFI_IP6_CONFIG_POLICY Policy;
1549 EFI_STATUS Status;
1550 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
1551 UINTN DataSize;
1552
1553 Ip6Cfg = Private->Ip6Cfg;
1554 DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
1555
1556 //
1557 // Get and store the current policy of IP6 driver.
1558 //
1559 Status = Ip6Cfg->GetData (
1560 Ip6Cfg,
1561 Ip6ConfigDataTypePolicy,
1562 &DataSize,
1563 &Private->Ip6Policy
1564 );
1565 if (EFI_ERROR (Status)) {
1566 return Status;
1567 }
1568
1569 if (Private->Ip6Policy == Ip6ConfigPolicyManual) {
1570 Policy = Ip6ConfigPolicyAutomatic;
1571 Status = Ip6Cfg->SetData (
1572 Ip6Cfg,
1573 Ip6ConfigDataTypePolicy,
1574 sizeof(EFI_IP6_CONFIG_POLICY),
1575 &Policy
1576 );
1577 if (EFI_ERROR (Status)) {
1578 //
1579 // There is no need to recover later.
1580 //
1581 Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;
1582 }
1583 }
1584
1585 return Status;
1586 }
1587
1588 /**
1589 This function will register the station IP address and flush IP instance to start using the new IP address.
1590
1591 @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
1592
1593 @retval EFI_SUCCESS The new IP address has been configured successfully.
1594 @retval Others Failed to configure the address.
1595
1596 **/
1597 EFI_STATUS
1598 PxeBcSetIp6Address (
1599 IN PXEBC_PRIVATE_DATA *Private
1600 )
1601 {
1602 EFI_STATUS Status;
1603 EFI_DHCP6_PROTOCOL *Dhcp6;
1604
1605 Dhcp6 = Private->Dhcp6;
1606
1607 CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_IPv6_ADDRESS));
1608 CopyMem (&Private->PxeBc.Mode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
1609
1610 Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);
1611 if (EFI_ERROR (Status)) {
1612 Dhcp6->Stop (Dhcp6);
1613 return Status;
1614 }
1615
1616 Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL);
1617 if (EFI_ERROR (Status)) {
1618 PxeBcUnregisterIp6Address (Private);
1619 Dhcp6->Stop (Dhcp6);
1620 return Status;
1621 }
1622
1623 AsciiPrint ("\n Station IP address is ");
1624 PxeBcShowIp6Addr (&Private->StationIp.v6);
1625
1626 return EFI_SUCCESS;
1627 }
1628
1629 /**
1630 EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
1631 to intercept events that occurred in the configuration process.
1632
1633 @param[in] This The pointer to the EFI DHCPv6 Protocol.
1634 @param[in] Context The pointer to the context set by EFI_DHCP6_PROTOCOL.Configure().
1635 @param[in] CurrentState The current operational state of the EFI DHCPv Protocol driver.
1636 @param[in] Dhcp6Event The event that occurs in the current state, which usually means a
1637 state transition.
1638 @param[in] Packet The DHCPv6 packet that is going to be sent or was already received.
1639 @param[out] NewPacket The packet that is used to replace the Packet above.
1640
1641 @retval EFI_SUCCESS Told the EFI DHCPv6 Protocol driver to continue the DHCP process.
1642 @retval EFI_NOT_READY Only used in the Dhcp6Selecting state. The EFI DHCPv6 Protocol
1643 driver will continue to wait for more packets.
1644 @retval EFI_ABORTED Told the EFI DHCPv6 Protocol driver to abort the current process.
1645
1646 **/
1647 EFI_STATUS
1648 EFIAPI
1649 PxeBcDhcp6CallBack (
1650 IN EFI_DHCP6_PROTOCOL *This,
1651 IN VOID *Context,
1652 IN EFI_DHCP6_STATE CurrentState,
1653 IN EFI_DHCP6_EVENT Dhcp6Event,
1654 IN EFI_DHCP6_PACKET *Packet,
1655 OUT EFI_DHCP6_PACKET **NewPacket OPTIONAL
1656 )
1657 {
1658 PXEBC_PRIVATE_DATA *Private;
1659 EFI_PXE_BASE_CODE_MODE *Mode;
1660 EFI_PXE_BASE_CODE_CALLBACK_PROTOCOL *Callback;
1661 EFI_DHCP6_PACKET *SelectAd;
1662 EFI_STATUS Status;
1663 BOOLEAN Received;
1664
1665 if ((Dhcp6Event != Dhcp6RcvdAdvertise) &&
1666 (Dhcp6Event != Dhcp6SelectAdvertise) &&
1667 (Dhcp6Event != Dhcp6SendSolicit) &&
1668 (Dhcp6Event != Dhcp6SendRequest) &&
1669 (Dhcp6Event != Dhcp6RcvdReply)) {
1670 return EFI_SUCCESS;
1671 }
1672
1673 ASSERT (Packet != NULL);
1674
1675 Private = (PXEBC_PRIVATE_DATA *) Context;
1676 Mode = Private->PxeBc.Mode;
1677 Callback = Private->PxeBcCallback;
1678
1679 //
1680 // Callback to user when any traffic ocurred if has.
1681 //
1682 if (Dhcp6Event != Dhcp6SelectAdvertise && Callback != NULL) {
1683 Received = (BOOLEAN) (Dhcp6Event == Dhcp6RcvdAdvertise || Dhcp6Event == Dhcp6RcvdReply);
1684 Status = Callback->Callback (
1685 Callback,
1686 Private->Function,
1687 Received,
1688 Packet->Length,
1689 (EFI_PXE_BASE_CODE_PACKET *) &Packet->Dhcp6
1690 );
1691 if (Status != EFI_PXE_BASE_CODE_CALLBACK_STATUS_CONTINUE) {
1692 return EFI_ABORTED;
1693 }
1694 }
1695
1696 Status = EFI_SUCCESS;
1697
1698 switch (Dhcp6Event) {
1699
1700 case Dhcp6SendSolicit:
1701 //
1702 // Record the first Solicate msg time
1703 //
1704 if (Private->SolicitTimes == 0) {
1705 CalcElapsedTime (Private);
1706 Private->SolicitTimes++;
1707 }
1708 //
1709 // Cache the dhcp discover packet to mode data directly.
1710 //
1711 CopyMem (&Mode->DhcpDiscover.Dhcpv4, &Packet->Dhcp6, Packet->Length);
1712 break;
1713
1714 case Dhcp6RcvdAdvertise:
1715 Status = EFI_NOT_READY;
1716 if (Private->OfferNum < PXEBC_OFFER_MAX_NUM) {
1717 //
1718 // Cache the dhcp offers to OfferBuffer[] for select later, and record
1719 // the OfferIndex and OfferCount.
1720 //
1721 PxeBcCacheDhcp6Offer (Private, Packet);
1722 }
1723 break;
1724
1725 case Dhcp6SendRequest:
1726 //
1727 // Store the request packet as seed packet for discover.
1728 //
1729 if (Private->Dhcp6Request != NULL) {
1730 FreePool (Private->Dhcp6Request);
1731 }
1732 Private->Dhcp6Request = AllocateZeroPool (Packet->Size);
1733 if (Private->Dhcp6Request != NULL) {
1734 CopyMem (Private->Dhcp6Request, Packet, Packet->Size);
1735 }
1736 break;
1737
1738 case Dhcp6SelectAdvertise:
1739 //
1740 // Select offer by the default policy or by order, and record the SelectIndex
1741 // and SelectProxyType.
1742 //
1743 PxeBcSelectDhcp6Offer (Private);
1744
1745 if (Private->SelectIndex == 0) {
1746 Status = EFI_ABORTED;
1747 } else {
1748 ASSERT (NewPacket != NULL);
1749 SelectAd = &Private->OfferBuffer[Private->SelectIndex - 1].Dhcp6.Packet.Offer;
1750 *NewPacket = AllocateZeroPool (SelectAd->Size);
1751 ASSERT (*NewPacket != NULL);
1752 CopyMem (*NewPacket, SelectAd, SelectAd->Size);
1753 }
1754 break;
1755
1756 case Dhcp6RcvdReply:
1757 //
1758 // Cache the dhcp ack to Private->Dhcp6Ack, but it's not the final ack in mode data
1759 // without verification.
1760 //
1761 ASSERT (Private->SelectIndex != 0);
1762 PxeBcCopyDhcp6Ack (Private, Packet, FALSE);
1763 break;
1764
1765 default:
1766 ASSERT (0);
1767 }
1768
1769 return Status;
1770 }
1771
1772
1773 /**
1774 Build and send out the request packet for the bootfile, and parse the reply.
1775
1776 @param[in] Private The pointer to PxeBc private data.
1777 @param[in] Type PxeBc option boot item type.
1778 @param[in] Layer The pointer to option boot item layer.
1779 @param[in] UseBis Use BIS or not.
1780 @param[in] DestIp The pointer to the server address.
1781
1782 @retval EFI_SUCCESS Successfully discovered the boot file.
1783 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
1784 @retval EFI_NOT_FOUND Can't get the PXE reply packet.
1785 @retval Others Failed to discover the boot file.
1786
1787 **/
1788 EFI_STATUS
1789 PxeBcDhcp6Discover (
1790 IN PXEBC_PRIVATE_DATA *Private,
1791 IN UINT16 Type,
1792 IN UINT16 *Layer,
1793 IN BOOLEAN UseBis,
1794 IN EFI_IP_ADDRESS *DestIp
1795 )
1796 {
1797 EFI_PXE_BASE_CODE_UDP_PORT SrcPort;
1798 EFI_PXE_BASE_CODE_UDP_PORT DestPort;
1799 EFI_PXE_BASE_CODE_MODE *Mode;
1800 EFI_PXE_BASE_CODE_PROTOCOL *PxeBc;
1801 EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover;
1802 UINTN DiscoverLen;
1803 EFI_DHCP6_PACKET *Request;
1804 UINTN RequestLen;
1805 EFI_DHCP6_PACKET *Reply;
1806 UINT8 *RequestOpt;
1807 UINT8 *DiscoverOpt;
1808 UINTN ReadSize;
1809 UINT16 OpFlags;
1810 UINT16 OpCode;
1811 UINT16 OpLen;
1812 UINT32 Xid;
1813 EFI_STATUS Status;
1814
1815 PxeBc = &Private->PxeBc;
1816 Mode = PxeBc->Mode;
1817 Request = Private->Dhcp6Request;
1818 SrcPort = PXEBC_BS_DISCOVER_PORT;
1819 DestPort = PXEBC_BS_DISCOVER_PORT;
1820 OpFlags = 0;
1821
1822 if (!UseBis && Layer != NULL) {
1823 *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK;
1824 }
1825
1826 if (Request == NULL) {
1827 return EFI_DEVICE_ERROR;
1828 }
1829
1830 Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET));
1831 if (Discover == NULL) {
1832 return EFI_OUT_OF_RESOURCES;
1833 }
1834
1835 //
1836 // Build the discover packet by the cached request packet before.
1837 //
1838 Xid = NET_RANDOM (NetRandomInitSeed ());
1839 Discover->TransactionId = HTONL (Xid);
1840 Discover->MessageType = Request->Dhcp6.Header.MessageType;
1841 RequestOpt = Request->Dhcp6.Option;
1842 DiscoverOpt = Discover->DhcpOptions;
1843 DiscoverLen = sizeof (EFI_DHCP6_HEADER);
1844 RequestLen = DiscoverLen;
1845
1846 while (RequestLen < Request->Length) {
1847 OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode);
1848 OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen);
1849 if (OpCode != EFI_DHCP6_IA_TYPE_NA &&
1850 OpCode != EFI_DHCP6_IA_TYPE_TA) {
1851 //
1852 // Copy all the options except IA option.
1853 //
1854 CopyMem (DiscoverOpt, RequestOpt, OpLen + 4);
1855 DiscoverOpt += (OpLen + 4);
1856 DiscoverLen += (OpLen + 4);
1857 }
1858 RequestOpt += (OpLen + 4);
1859 RequestLen += (OpLen + 4);
1860 }
1861
1862 Status = PxeBc->UdpWrite (
1863 PxeBc,
1864 OpFlags,
1865 &Private->ServerIp,
1866 &DestPort,
1867 NULL,
1868 &Private->StationIp,
1869 &SrcPort,
1870 NULL,
1871 NULL,
1872 &DiscoverLen,
1873 (VOID *) Discover
1874 );
1875 if (EFI_ERROR (Status)) {
1876 return Status;
1877 }
1878
1879 //
1880 // Cache the right PXE reply packet here, set valid flag later.
1881 // Especially for PXE discover packet, store it into mode data here.
1882 //
1883 if (Private->IsDoDiscover) {
1884 CopyMem (&Mode->PxeDiscover.Dhcpv6, Discover, DiscoverLen);
1885 Reply = &Private->PxeReply.Dhcp6.Packet.Ack;
1886 } else {
1887 Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer;
1888 }
1889 ReadSize = (UINTN) Reply->Size;
1890
1891 //
1892 // Start Udp6Read instance
1893 //
1894 Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData);
1895 if (EFI_ERROR (Status)) {
1896 return Status;
1897 }
1898
1899 Status = PxeBc->UdpRead (
1900 PxeBc,
1901 OpFlags,
1902 &Private->StationIp,
1903 &SrcPort,
1904 &Private->ServerIp,
1905 &DestPort,
1906 NULL,
1907 NULL,
1908 &ReadSize,
1909 (VOID *) &Reply->Dhcp6
1910 );
1911 //
1912 // Stop Udp6Read instance
1913 //
1914 Private->Udp6Read->Configure (Private->Udp6Read, NULL);
1915 if (EFI_ERROR (Status)) {
1916 return Status;
1917 }
1918
1919 return EFI_SUCCESS;
1920 }
1921
1922
1923 /**
1924 Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
1925
1926 @param[in] Private The pointer to PxeBc private data.
1927 @param[in] Dhcp6 The pointer to the EFI_DHCP6_PROTOCOL
1928
1929 @retval EFI_SUCCESS The S.A.R.R. process successfully finished.
1930 @retval Others Failed to finish the S.A.R.R. process.
1931
1932 **/
1933 EFI_STATUS
1934 PxeBcDhcp6Sarr (
1935 IN PXEBC_PRIVATE_DATA *Private,
1936 IN EFI_DHCP6_PROTOCOL *Dhcp6
1937 )
1938 {
1939 EFI_PXE_BASE_CODE_MODE *PxeMode;
1940 EFI_DHCP6_CONFIG_DATA Config;
1941 EFI_DHCP6_MODE_DATA Mode;
1942 EFI_DHCP6_RETRANSMISSION *Retransmit;
1943 EFI_DHCP6_PACKET_OPTION *OptList[PXEBC_DHCP6_OPTION_MAX_NUM];
1944 UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE];
1945 UINT32 OptCount;
1946 EFI_STATUS Status;
1947 EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
1948 EFI_STATUS TimerStatus;
1949 EFI_EVENT Timer;
1950 UINT64 GetMappingTimeOut;
1951 UINTN DataSize;
1952 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits;
1953
1954 Status = EFI_SUCCESS;
1955 PxeMode = Private->PxeBc.Mode;
1956 Ip6Cfg = Private->Ip6Cfg;
1957 Timer = NULL;
1958
1959 //
1960 // Build option list for the request packet.
1961 //
1962 OptCount = PxeBcBuildDhcp6Options (Private, OptList, Buffer);
1963 ASSERT (OptCount> 0);
1964
1965 Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION));
1966 if (Retransmit == NULL) {
1967 return EFI_OUT_OF_RESOURCES;
1968 }
1969
1970 ZeroMem (&Mode, sizeof (EFI_DHCP6_MODE_DATA));
1971 ZeroMem (&Config, sizeof (EFI_DHCP6_CONFIG_DATA));
1972
1973 Config.OptionCount = OptCount;
1974 Config.OptionList = OptList;
1975 Config.Dhcp6Callback = PxeBcDhcp6CallBack;
1976 Config.CallbackContext = Private;
1977 Config.IaInfoEvent = NULL;
1978 Config.RapidCommit = FALSE;
1979 Config.ReconfigureAccept = FALSE;
1980 Config.IaDescriptor.IaId = Private->IaId;
1981 Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA;
1982 Config.SolicitRetransmission = Retransmit;
1983 Retransmit->Irt = 4;
1984 Retransmit->Mrc = 4;
1985 Retransmit->Mrt = 32;
1986 Retransmit->Mrd = 60;
1987
1988 //
1989 // Configure the DHCPv6 instance for PXE boot.
1990 //
1991 Status = Dhcp6->Configure (Dhcp6, &Config);
1992 FreePool (Retransmit);
1993 if (EFI_ERROR (Status)) {
1994 return Status;
1995 }
1996
1997 //
1998 // Initialize the record fields for DHCPv6 offer in private data.
1999 //
2000 Private->IsProxyRecved = FALSE;
2001 Private->OfferNum = 0;
2002 Private->SelectIndex = 0;
2003 ZeroMem (Private->OfferCount, sizeof (Private->OfferCount));
2004 ZeroMem (Private->OfferIndex, sizeof (Private->OfferIndex));
2005
2006
2007 //
2008 // Start DHCPv6 S.A.R.R. process to acquire IPv6 address.
2009 //
2010 Status = Dhcp6->Start (Dhcp6);
2011 if (Status == EFI_NO_MAPPING) {
2012 //
2013 // IP6 Linklocal address is not available for use, so stop current Dhcp process
2014 // and wait for duplicate address detection to finish.
2015 //
2016 Dhcp6->Stop (Dhcp6);
2017
2018 //
2019 // Get Duplicate Address Detection Transmits count.
2020 //
2021 DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS);
2022 Status = Ip6Cfg->GetData (
2023 Ip6Cfg,
2024 Ip6ConfigDataTypeDupAddrDetectTransmits,
2025 &DataSize,
2026 &DadXmits
2027 );
2028 if (EFI_ERROR (Status)) {
2029 Dhcp6->Configure (Dhcp6, NULL);
2030 return Status;
2031 }
2032
2033 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
2034 if (EFI_ERROR (Status)) {
2035 Dhcp6->Configure (Dhcp6, NULL);
2036 return Status;
2037 }
2038
2039 GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY;
2040 Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut);
2041 if (EFI_ERROR (Status)) {
2042 gBS->CloseEvent (Timer);
2043 Dhcp6->Configure (Dhcp6, NULL);
2044 return Status;
2045 }
2046
2047 do {
2048
2049 TimerStatus = gBS->CheckEvent (Timer);
2050 if (!EFI_ERROR (TimerStatus)) {
2051 Status = Dhcp6->Start (Dhcp6);
2052 }
2053 } while (TimerStatus == EFI_NOT_READY);
2054
2055 gBS->CloseEvent (Timer);
2056 }
2057 if (EFI_ERROR (Status)) {
2058 if (Status == EFI_ICMP_ERROR) {
2059 PxeMode->IcmpErrorReceived = TRUE;
2060 }
2061 Dhcp6->Configure (Dhcp6, NULL);
2062 return Status;
2063 }
2064
2065 //
2066 // Get the acquired IPv6 address and store them.
2067 //
2068 Status = Dhcp6->GetModeData (Dhcp6, &Mode, NULL);
2069 if (EFI_ERROR (Status)) {
2070 Dhcp6->Stop (Dhcp6);
2071 return Status;
2072 }
2073
2074 ASSERT (Mode.Ia->State == Dhcp6Bound);
2075 //
2076 // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
2077 // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
2078 // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
2079 // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
2080 // to find a valid router address.
2081 //
2082 CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
2083
2084 //
2085 // Check the selected offer whether BINL retry is needed.
2086 //
2087 Status = PxeBcHandleDhcp6Offer (Private);
2088 if (EFI_ERROR (Status)) {
2089 Dhcp6->Stop (Dhcp6);
2090 return Status;
2091 }
2092
2093 return EFI_SUCCESS;
2094 }