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