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