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