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