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