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