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